【问题标题】:old generation space utlization in JVMJVM中的老年代空间利用率
【发布时间】:2012-12-02 15:34:48
【问题描述】:

据我所知,对于老一代JVM的空间,它可以用于两个目的,

  1. 用于从年轻代提升到老年代的对象?
  2. 用于特殊用例中的新对象分配(https://stackoverflow.com/questions/9053144/will-i-encounter-java-lang-outofmemoryerror-even-with-no-lack-of-memory)

我的问题是,

  1. 是否还有其他可以利用老年代空间的用例?
  2. 我认为将对象从年轻代复制到老年代涉及到内存复制,是深拷贝还是浅拷贝?

提前致谢, 林

【问题讨论】:

  • 你的记忆力是否持续增加?你在使用静态地图之类的吗?
  • 嗨@Narendra,我正在尝试了解 GC 的一些基础知识,因为我可能需要调整写入繁重的应用程序。
  • 好的。因为内存泄漏导致Old generation不断增加。这就是为什么这样的问题
  • 嗨@Narendra,你是什么意思“内存泄漏导致老年代不断增加”?有参考文件吗?
  • 没有任何引用,但是在内存泄漏中,对象在 GC 循环期间没有被释放,它们不断提升,最终将导致填充老年代。

标签: java garbage-collection jvm


【解决方案1】:

让我回答 2。它绝对不是深度复制:GC 将对象作为不同的内存块处理,而深度复制实际上仅意味着复制许多连接到对象图中的不同对象。此外,想象一个移动,而不是复制,会更好地为您服务;复制其实只是一个“实现细节”,想要的效果就是重定位。

【讨论】:

  • 谢谢@Marko,是的,我同意使用 move 是一个更好的选择。其实我的问题是,1.它真的是作为一个整体移动的,或者只是移动一个参考。例如,有一个对象是一个包含 1M 个字符的缓冲区,当将缓冲区对象从年轻代提升到老年代时,我们是否移动整个 1M 字符,2.假设有一个被提升的对象,我们是否移动它的整个对象图(即使图上的某些对象不符合提升条件)?如果没有,GC 会处理修复对象图中的对象引用更新问题吗?
  • 在考虑 GC 时忘记封装。它将您的 rbuffer 对象视为一个小结构,并将 1M 数组视为一个单独的块。它们完全相互独立。请注意,无论您移动对象图还是仅移动根对象,都需要修复指针。指针不是相对的。是的,当提升到 Tenured 一代时,整个数组将被重新定位(复制),除非它太大以至于一开始就被分配到那里。
  • 感谢@Marko 的详细部署。让我通过重复我的话来确认我的理解是正确的,1.引用/指针由GC固定2.GC将独立处理每个对象(提升或移动),而不是将对象图视为一个整体来提升(或移动)?
  • 顺便说一句:您对原始问题中我的问题 1 的 cmets 是什么? :-)
  • 是的,你做对了。至于你的第一个问题,我不知道在终身代中分配内存的任何其他途径,但我不知道没有其他方法。
【解决方案2】:

将此代码用于回答@Lin Ma 在他的评论中提出的问题:

class SomeClass{
    private static List<Object> memoryLeakCulprit = new ArrayList<Object>();



    void someMethod(Object obj){

          //adding the reference of some object in the culprit list
          memoryLeakCulprit.add(obj);

    }

    //supposed to remove the reference passed
    void someOtherMethod(Object obj){

         obj = null;

         //bummer forgot to remove the reference from list

         //now the instance is not reachable by obj
         //so now as new references are added to culprit list the memory will keep on increasing in size

    }

}

UDPATE

如何解决这个漏洞

oid someOtherMethod(Object obj){

              //before setting the obj reference to null it must be removed from culprit list
              memoryLeakCulprit.remove(obj);

              //now its safe to set this reference to null
              obj = null;

        }

解决泄漏的唯一方法是使用一些分析工具(例如 JProfilerVisualVMProfile 应用程序并找出哪个类是导致泄漏。

找到课程后,代码必须更改,这是唯一的方法。

在程序退出之前无需释放引用。原因是 static 变量 (memoryLeakCulprit) 绑定到 Class 对象,一旦您退出程序,所有引用都会自动释放,包括 Class 对象。

另一方面,请务必在退出程序之前关闭系统资源(套接字、数据库连接)。

【讨论】:

  • 嗨@Narendra,我认为在您的示例中,该对象是由memoryLeakCulprit 引用的,所以该对象不是GCed?我认为对象没有被GCed,当有任何引用时,你为什么认为有泄漏?谢谢。
  • @LinMa 我想你对 Leak 有误解,这是一个经常出现的编程错误。因为这里只是一个小程序,所以很容易确定。但是当有 1000K LOC 时,就不是那么容易了。这就是人们使用堆转储和 JConsole 类型的应用程序来查找泄漏的原因。这是一个编程错误!
  • 引用维基百科:计算机科学中的内存泄漏(或在此上下文中的泄漏)发生在计算机程序获取内存但未能将其释放回操作系统时。[1]在面向对象编程中,当对象存储在内存中但运行代码无法访问时,可能会发生内存泄漏。
  • @LinMa 是的,如果您从静态列表中删除引用,那么只有列表将保留到程序退出,其他的将被释放。太好了,我想现在你明白了!!尽管如此,如果你有什么想法,总是喜欢参与建设性的讨论。 :)
  • @LinMa 把它传给像你这样的人,这相当于开派对 :) 干杯!
猜你喜欢
  • 2020-05-16
  • 1970-01-01
  • 2011-09-09
  • 2019-03-14
  • 1970-01-01
  • 2020-02-29
  • 1970-01-01
  • 1970-01-01
  • 2021-10-24
相关资源
最近更新 更多