Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 不使用SimpleDataFormatter(产生垃圾)格式化毫秒到日期字符串_Java - Fatal编程技术网

Java 不使用SimpleDataFormatter(产生垃圾)格式化毫秒到日期字符串

Java 不使用SimpleDataFormatter(产生垃圾)格式化毫秒到日期字符串,java,Java,我正在寻找一个日期格式化程序的Java实现,其长度为毫秒。我不想使用SimpleDataFormatter,因为它会向GC产生垃圾。我正在寻找一个快速且无垃圾的Java实现。有人在什么地方见过吗 StringBuilder sb = getReusableStringBuilder(); parse(sb, System.currentTimeMillis()); 编辑:这是一个日志库,所以它必须包括时间。这里有一个后台记录器,记录时间/日期,还有一个StringBuilder,完全在后台记

我正在寻找一个日期格式化程序的Java实现,其长度为毫秒。我不想使用SimpleDataFormatter,因为它会向GC产生垃圾。我正在寻找一个快速且无垃圾的Java实现。有人在什么地方见过吗

StringBuilder sb = getReusableStringBuilder();

parse(sb, System.currentTimeMillis());

编辑:这是一个日志库,所以它必须包括时间。

这里有一个后台记录器,记录时间/日期,还有一个StringBuilder,完全在后台记录。每次呼叫的典型延迟低于一微秒。它回收所有东西,因此不会产生GC

这比使用队列在两个线程之间传递工作要高效得多。所有队列实现都会创建垃圾:(


当您需要处理任何与日期和时间相关的内容时,请始终使用。它还包含格式化程序。

解决方案比我想象的要简单得多:引导FieldPosition,这样它就不会泄漏内存。

我使用DateTimes实用程序类创建了库,用于此目的。它在内部采用“长值”自1970/01/01 00:00:00.000以来的毫秒数,并计算年、月、日、小时、分钟、秒和毫秒值。然后将此信息作为ASCII字符串放入提供的字节数组中,GC没有新对象。此字节数组可以使用System.out.write()方法打印到控制台,而无需创建新的字符串对象


您可以从我的网站上以jar文件的形式获取该库。文章描述了使用情况并比较了性能。

如果您不想产生垃圾,请不要使用垃圾收集语言。为什么您会关心SimpleDataFormat产生的垃圾?如果避免垃圾是您的目标,那么为什么您会变得完全有效
long
不可处理地有效(可能可以避免)首先是
String
对象?您是否检查了
SimpleDataFormat
产生的垃圾量?特别是如果您使用的话?因为我希望垃圾量很小。@Peter Lawrey:这是我的观点。这看起来像是过早优化。要么日志级别设置为跟踪,要么日志代码会经常执行,but调用代码将生成比日志库本身多得多的垃圾(例如,必须记录的所有字符串),或者它被设置为错误,生成一些垃圾不会造成任何伤害,因为它不会经常被调用。@Raedwald:我永远不会这样做。您可以从StringBuilder中获取内容,而不创建字符串。也许您可以解释如何使用它,使它生成最小GC。我会使用StringBuilder不生成字符串,因此格式化逻辑c会写信给StringBuilder。我正在改变我的问题以澄清这一点。你的方法很酷,Peter。我不介意缓存日期并只计算每个日志上的时间。但是时间逻辑可能会很痛苦,特别是白天节省时间、时区等。在开始自己编写代码之前,我想花点时间看看是否可以完成重复使用
FieldPosition
将平均内存使用量减少到24个字节(再少32个字节!)。这可能是节省,因为您已经共享了
SimpleDataFormat
StringBuffer
,所以无论如何它都需要以某种方式进行同步。@Peter:测量内存使用量的非常酷的方法,我不知道
UseTLAB
。我真的想不止一次地+1这个答案。@Sergio Olivera Jr.,您可以使用
ThreadLocal
用于日志记录。由于没有人指导我使用实现格式化逻辑的代码,因此如果没有其他问题,我将选择此答案。
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class BackgroundLogger implements Runnable {
  static final int ENTRIES = 64;

  static class LogEntry {
    long time;
    int level;
    final StringBuilder text = new StringBuilder();
  }

  static class LogEntries {
    final LogEntry[] lines = new LogEntry[ENTRIES];
    int used = 0;
  }

  private final ExecutorService executor = Executors.newSingleThreadExecutor();
  final Exchanger<LogEntries> logEntriesExchanger = new Exchanger<LogEntries>();
  LogEntries entries = new LogEntries();

  BackgroundLogger() {
    executor.submit(this);
  }

  // put whatever you want in the StringBuilder, before the next call!
  public StringBuilder log(int level) {
    try {
      if (entries.used == ENTRIES)
        entries = logEntriesExchanger.exchange(entries);
      LogEntry le = entries.lines[entries.used++];
      le.time = System.currentTimeMillis();
      le.level = level;
      return le.text;

    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
  }

  public void flush() throws InterruptedException {
    entries = logEntriesExchanger.exchange(entries);
    entries = logEntriesExchanger.exchange(entries);
  }

  public void stop() {
    try {
      flush();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    executor.shutdownNow();
  }

  @Override
  public void run() {
    LogEntries entries = new LogEntries();
    try {
      while(!Thread.interrupted()) {
        entries = logEntriesExchanger.exchange(entries);
        for (int i = 0; i < entries.used; i++) {
          bgLog(entries.lines[i]);
          entries.lines[i].text.delete(0, entries.lines[i].text.length());
        }
        entries.used = 0;
      }
    } catch (InterruptedException ignored) {

    } finally {
      System.out.println("logger stopping.");
    }
  }

  private void bgLog(LogEntry line) {
    // log the entry to a file.
  }
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
StringBuffer sb = new StringBuffer();
Date tmpDate = new Date();
final FieldPosition pos = new FieldPosition(0);
{
  long free1 = Runtime.getRuntime().freeMemory();
  for (int i = 0; i < 1000; i++) {
    tmpDate.setTime(System.currentTimeMillis());
    sdf.format(tmpDate, sb, pos);
    sb.delete(0, sb.length());
  }
  long free2 = Runtime.getRuntime().freeMemory();
  if (free1 == free2) throw new Error("This must be run with -XX:-UseTLAB");
  System.out.println("SDF.format used an average of " + (free1 - free2) / 1000 + " bytes");
}
{
  long free1 = Runtime.getRuntime().freeMemory();
  for (int i = 0; i < 1000; i++) {
    tmpDate.setTime(System.currentTimeMillis());
    sdf.format(tmpDate, sb, pos);
    String str = sb.toString();
    sb.delete(0, sb.length());
  }
  long free2 = Runtime.getRuntime().freeMemory();
  if (free1 == free2) throw new Error("This must be run with -XX:-UseTLAB");
  System.out.println("SDF.format with a String used an average of " + (free1 - free2) / 1000 + " bytes");
}
SDF.format used an average of 24 bytes
SDF.format with a String used an average of 120 bytes