【问题标题】:String creation in local method and heap memory在本地方法和堆内存中创建字符串
【发布时间】:2020-03-24 14:22:00
【问题描述】:

我在一个类中有一个方法,我在其中创建了这样的字符串:

private void log(HttpServletRequest request, HttpServletResponse response) {
    String result = "Following request " + request.getRequestURI() + " yielded " + response.getStatus();
    log.info(result);
}

我的问题是,result 字符串被生成了数百万次。对堆内存有影响吗?

我目前的理解是每个方法都有自己的堆内存分配。方法执行完毕后,所有局部变量都会从内存中消失。

我的另一个理解是字符串存储在全局堆内存中,它们会在下一个垃圾回收周期被清理。

有人能说明一下吗,我将不胜感激。

【问题讨论】:

  • Java 可以随意使用内存,永远不要依赖它。 Java 将最终清理未使用的实例,包括仅在方法中知道的本地字符串。请注意,尽管您将其传递给log(但我想在记录后很快就会释放字符串)。
  • 无论如何,您在这里也无能为力(如果您想保留日志,那就是)。 Java 已经将+ 调用转换为StringBuilder 用法(自Java 9 起甚至更好),所以这部分已经很好了。而且您无法在编译时计算字符串,因为 URI 和响应状态每次都会更改。唯一可以优化的就是去掉临时变量result。相反,直接在log.info(...) 调用中创建字符串。但仅此而已。
  • JIT 编译器应该已经为您优化掉了局部变量,所以即使这样也没有必要。

标签: java


【解决方案1】:

由于字符串result只在方法中使用,并且在方法返回后不会保留对该字符串的引用,所以字符串为garbage,这意味着分配给它的内存可以被释放并随后用于某些事情否则。

Java 是一种垃圾收集语言,因此这会在运行时自动发生,您无需编写任何代码来显式释放内存。这可能随时发生;字符串对象的内存可以立即释放,也可以每调用该方法一百次就释放一次,也可以随机释放,或者直到程序结束才释放。根据规范,所有这些行为都是可能的。

请注意,字符串保证在堆上分配。允许 Java 实现在堆栈上分配对象,只要 escape analysis 表明一旦方法返回就不会引用该对象。这实际上至少在某些实现中已经完成;请参阅 this other questionthis one 进行讨论。如果字符串是在堆栈上分配的,那么它会立即被有效地进行垃圾回收。

但是,无论您的编译器或解释器做什么,它都不会对程序的行为产生任何影响。进行这些优化只是因为它们不会影响程序行为。

【讨论】:

    【解决方案2】:

    该方法每次执行时,都会在堆内存中创建一个String对象,并在栈上为其分配一个本地引用。这个本地引用将被传递给log.info(),并假设该方法不会将结果保存在任何地方,一旦它返回,堆中的该对象将有资格进行垃圾回收。

    只要您的result 没有永久引用它,它就不会对您的程序内存产生永久影响。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-09
      • 1970-01-01
      • 2013-04-15
      • 2017-07-13
      • 1970-01-01
      • 2015-04-28
      • 1970-01-01
      相关资源
      最近更新 更多