首页 > 试题广场 >

下面哪种情况会导致持久区jvm堆内存溢出?

[单选题]
下面哪种情况会导致持久区jvm堆内存溢出?
  • 循环上万次的字符串处理
  • 在一段代码内申请上百M甚至上G的内存
  • 使用CGLib技术直接操作字节码运行,生成大量的动态类
  • 不断创建对象
建议看看这篇博客 入门 通俗易懂 http://blog.csdn.net/sivyer123/article/details/17139443
简单的来说 java的堆内存分为两块:permantspace(持久带) 和 heap space。
持久带中主要存放用于存放静态类型数据,如 Java Class, Method 等, 与垃圾收集器要收集的Java对象关系不大。
而heapspace分为年轻带和年老带 
年轻代的垃圾回收叫 Young GC, 年老代的垃圾回收叫 Full GC。
在年轻代中经历了N次(可配置)垃圾回收后仍然存活的对象,就会被复制到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象
年老代溢出原因有  循环上万次的字符串处理、创建上千万个对象、在一段代码内申请上百M甚至上G的内存,既A B D选项
持久代溢出原因  动态加载了大量Java类而导致溢出
发表于 2015-08-16 14:04:29 回复(44)
A,B,D都将会导致堆内存年老代溢出,堆内存分为Perment Space和Heap Space,前者存放静态类型数据,如java class,method等,年老代中存放一些生命周期较长的对象,而新生成的对象都是存放在年轻代中

编辑于 2015-07-06 10:47:36 回复(0)
一个对象的一生:我是一个普通的Java对象,我出生在Eden区,在Eden区我还看到和我长的很像的小兄弟,我们在Eden区中玩了挺长时间。有一天Eden区中的人实在是太多了,我就被迫去了Survivor区的“From”区,自从去了Survivor区,我就开始漂了,有时候在Survivor的“From”区,有时候在Survivor的“To”区,居无定所。直到我18岁的时候,爸爸说我成人了,该去社会上闯闯了。于是我就去了年老代那边,年老代里,人很多,并且年龄都挺大的,我在这里也认识了很多人。在年老代里,我生活了20年(每次GC加一岁),然后被回收。
发表于 2017-08-24 15:45:01 回复(33)
C
持久区存放运行时需要的Class和Interface的元数据,而对象存放在堆空间的新生代和年老代。BD选项只会导致堆空间的溢出。
发表于 2015-04-15 09:52:56 回复(0)
C
发表于 2015-01-03 21:29:56 回复(0)

堆内存设置

原理

JVM堆内存分为2块:Permanent Space 和 Heap Space。
  • Permanent 即 持久代(Permanent Generation),主要存放的是Java类定义信息,与垃圾收集器要收集的Java对象关系不大。
  • Heap = { Old + NEW = {Eden, from, to} },Old 即 年老代(Old Generation),New 即 年轻代(Young Generation)。年老代和年轻代的划分对垃圾收集影响比较大。

年轻代

所有新生成的对象首先都是放在年轻代。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代一般分3个区,1个Eden区,2个Survivor区(from 和 to)。

大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当一个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当另一个Survivor区也满了的时候,从前一个Survivor区复制过来的并且此时还存活的对象,将可能被复制到年老代。

2个Survivor区是对称的,没有先后关系,所以同一个Survivor区中可能同时存在从Eden区复制过来对象,和从另一个Survivor区复制过来的对象;而复制到年老区的只有从另一个Survivor区过来的对象。而且,因为需要交换的原因,Survivor区至少有一个是空的。特殊的情况下,根据程序需要,Survivor区是可以配置为多个的(多于2个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。

针对年轻代的垃圾回收即 Young GC。

年老代

在年轻代中经历了N次(可配置)垃圾回收后仍然存活的对象,就会被复制到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

针对年老代的垃圾回收即 Full GC。

持久代

用于存放静态类型数据,如 Java Class, Method 等。持久代对垃圾回收没有显著影响。但是有些应用可能动态生成或调用一些Class,例如 Hibernate CGLib 等,在这种时候往往需要设置一个比较大的持久代空间来存放这些运行过程中动态增加的类型。


所以,当一组对象生成时,内存申请过程如下:

  1. JVM会试图为相关Java对象在年轻代的Eden区中初始化一块内存区域。
  2. 当Eden区空间足够时,内存申请结束。否则执行下一步。
  3. JVM试图释放在Eden区中所有不活跃的对象(Young GC)。释放后若Eden空间仍然不足以放入新对象,JVM则试图将部分Eden区中活跃对象放入Survivor区。
  4. Survivor区被用来作为Eden区及年老代的中间交换区域。当年老代空间足够时,Survivor区中存活了一定次数的对象会被移到年老代。
  5. 当年老代空间不够时,JVM会在年老代进行完全的垃圾回收(Full GC)。
  6. Full GC后,若Survivor区及年老代仍然无法存放从Eden区复制过来的对象,则会导致JVM无法在Eden区为新生成的对象申请内存,即出现“Out of Memory”。

OOM(“Out of Memory”)异常一般主要有如下2种原因

1. 年老代溢出,表现为:java.lang.OutOfMemoryError:Javaheapspace
这是最常见的情况,产生的原因可能是:设置的内存参数Xmx过小或程序的内存泄露及使用不当问题。
例如循环上万次的字符串处理、创建上千万个对象、在一段代码内申请上百M甚至上G的内存。还有的时候虽然不会报内存溢出,却会使系统不间断的垃圾回收,也无法处理其它请求。这种情况下除了检查程序、打印堆内存等方法排查,还可以借助一些内存分析工具,比如MAT就很不错。

2. 持久代溢出,表现为:java.lang.OutOfMemoryError:PermGenspace
通常由于持久代设置过小,动态加载了大量Java类而导致溢出 ,解决办法唯有将参数 -XX:MaxPermSize 调大(一般256m能满足绝大多数应用程序需求)。将部分Java类放到容器共享区(例如Tomcat share lib)去加载的办法也是一个思路,但前提是容器里部署了多个应用,且这些应用有大量的共享类库
发表于 2016-08-06 11:35:54 回复(26)
说得简单一点,持久堆内存,即为存放字节码文件对象的地方,因为平时每个.class文件的对象都只有一份,此对象的唯一性由全限定类名和类加载器共同决定,正常编程时不会溢出,只有修改类加载器,生成大量的字节码文件对象,才会溢出。
编辑于 2015-08-17 19:38:22 回复(2)
持久代一般存放了要加载的类信息、静态变量、final类型的常量、属性和方法信息。
持久代想要溢出,与创建对象的,大量运行字符串没关系。只有操纵调用,类信息的东西才会影响到持久代。
类信息对应的就是操纵动态生成类等等。
发表于 2015-11-29 22:17:33 回复(2)
A:字符串的处理是操作堆栈
B:在一段代码中申请大量内存,也是向当前线程的栈堆申请内存,没有足够的内存会导致堆栈溢出
D:创建新的对象是存入堆内存,大量创建对象并不销毁,会让堆内存溢出
C:持久区也就是方法区,一般保存一些编译期已知常量,字符串常量池等,类的信息等,通过CGLIB操作字节码生成大量动态类,会导致大量字节码常量的出现,导致持久区溢出
发表于 2018-08-12 09:20:19 回复(1)
持久代仅仅是HotSpot存在的一个概念,并且将其置于方法区中,本质上两者并不等价的。而方法区在《深入理解Java虚拟机》书中被称为非堆(Non-heap),目的就是要跟存放对象实例的Java堆区分开来,在方法区主要存放的是已经被虚拟机加载的类信息、常量、静态常量等数据。
发表于 2018-08-23 21:44:10 回复(1)
这jdk8更新几年了还有这题
发表于 2022-07-23 22:01:36 回复(0)
ABD是年老代溢出的原因,咱们选C
发表于 2022-02-19 13:01:46 回复(0)
A、上万次String处理,但不一定有新String的创建
B、在一段代码内申请内存,不是消耗持久区jvm堆内存
C、持久区jvm堆(个人感觉说的是方法区), 方法区就是存放类信息、常量、静态变量、编译后的代码等的区域,C 生成大量的动态类,就会致持久区jvm堆内存溢出
D、不断创建对象,是消耗的  堆(Heap) 内存,因为对象实例几乎都是在堆(Heap)中分配空间的

发表于 2018-11-29 09:59:36 回复(0)
JVM内存:持久带 heap space
                  持久带:(主要存放静态类型的数据)内存溢出:使用CGLib技术直接操作字节码运行,生成大量的动态类
                                    持久带溢出原因:动态加载大量java类而导致溢出
                  heap space:年轻带,年老带 年老带溢出:循环上万次的字符串处理、创建上万个对象、在一段代码中申请上百M甚至上G的内存
发表于 2017-12-10 16:28:47 回复(1)

此外还有一个 持久代 : 用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过 -XX:MaxPermSize=<N> 进行设置。

有的虚拟机并没有持久代,JAVA8 开始持久代也已经被彻底删除了,取代它的是另一个内存区域也被称为 元空间

发表于 2016-07-22 15:15:04 回复(0)
C ,类是在持久区的,对象是在年轻代和年老代的。
发表于 2015-03-26 09:30:08 回复(0)
JDK1.6及以前,常量池在方法区,这时的方法区也叫做永久代;
永久代主要存放以下数据:
JVM internal representation of classes and their metadata //类及其元数据的JVM内部表示
Class statics //类的静态
Interned strings //实际字符串,说的就是常量池吧
JDK1.7的时候,方法区合并到了堆内存中,这时的常量池也可以说是在堆内存中;
从 JDK7 开始,JDK 开发者们就有消灭永久代的打算了。有部分数据移到永久代之外了:
Symbols => native memory // 符号引用 >本机内存
Interned strings => Java Heap // Interned string => Java堆
Class statics => Java Heap //类statics => Java堆
JDK1.8及以后,方法区又从堆内存中剥离出来了,但实现方式与之前的永久代不同,这时的方法区被叫做元空间,常量池就存储在元空间。

发表于 2022-01-07 18:18:24 回复(0)
这个问题的本质是方法区的溢出。 只有大量的出现静态信息,类信息才会出现。 那就只有字节码出现了,一直创建类,一直方法区增加。 当然,到1.8就没这事了
编辑于 2021-06-02 08:45:33 回复(0)
JDK1.7后,字符串常量池移入堆空间,当你循环几万次的字符串String创建时,会报堆内存溢出
发表于 2019-03-23 10:31:04 回复(0)
堆内存设置 原理 JVM堆内存分为2块:Permanent Space 和 Heap Space。 Permanent 即 持久代(Permanent Generation),主要存放的是Java类定义信息,与垃圾收集器要收集的Java对象关系不大。 Heap = { Old + NEW = {Eden, from, to} },Old 即 年老代(Old Generation),New 即 年轻代(Young Generation)。年老代和年轻代的划分对垃圾收集影响比较大。 年轻代 所有新生成的对象首先都是放在年轻代。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代一般分3个区,1个Eden区,2个Survivor区(from 和 to)。 大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当一个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当另一个Survivor区也满了的时候,从前一个Survivor区复制过来的并且此时还存活的对象,将可能被复制到年老代。 2个Survivor区是对称的,没有先后关系,所以同一个Survivor区中可能同时存在从Eden区复制过来对象,和从另一个Survivor区复制过来的对象;而复制到年老区的只有从另一个Survivor区过来的对象。而且,因为需要交换的原因,Survivor区至少有一个是空的。特殊的情况下,根据程序需要,Survivor区是可以配置为多个的(多于2个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。 针对年轻代的垃圾回收即 Young GC。 年老代 在年轻代中经历了N次(可配置)垃圾回收后仍然存活的对象,就会被复制到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。 针对年老代的垃圾回收即 Full GC。 持久代 用于存放静态类型数据,如 Java Class, Method 等。持久代对垃圾回收没有显著影响。但是有些应用可能动态生成或调用一些Class,例如 Hibernate CGLib 等,在这种时候往往需要设置一个比较大的持久代空间来存放这些运行过程中动态增加的类型。 所以,当一组对象生成时,内存申请过程如下: JVM会试图为相关Java对象在年轻代的Eden区中初始化一块内存区域。 当Eden区空间足够时,内存申请结束。否则执行下一步。 JVM试图释放在Eden区中所有不活跃的对象(Young GC)。释放后若Eden空间仍然不足以放入新对象,JVM则试图将部分Eden区中活跃对象放入Survivor区。 Survivor区被用来作为Eden区及年老代的中间交换区域。当年老代空间足够时,Survivor区中存活了一定次数的对象会被移到年老代。 当年老代空间不够时,JVM会在年老代进行完全的垃圾回收(Full GC)。 Full GC后,若Survivor区及年老代仍然无法存放从Eden区复制过来的对象,则会导致JVM无法在Eden区为新生成的对象申请内存,即出现“Out of Memory”。 OOM(“Out of Memory”)异常一般主要有如下2种原因: 1. 年老代溢出,表现为:java.lang.OutOfMemoryError:Javaheapspace 这是最常见的情况,产生的原因可能是:设置的内存参数Xmx过小或程序的内存泄露及使用不当问题。 例如循环上万次的字符串处理、创建上千万个对象、在一段代码内申请上百M甚至上G的内存。还有的时候虽然不会报内存溢出,却会使系统不间断的垃圾回收,也无法处理其它请求。这种情况下除了检查程序、打印堆内存等方法排查,还可以借助一些内存分析工具,比如MAT就很不错。 2. 持久代溢出,表现为:java.lang.OutOfMemoryError:PermGenspace 通常由于持久代设置过小,动态加载了大量Java类而导致溢出 ,解决办法唯有将参数 -XX:MaxPermSize 调大(一般256m能满足绝大多数应用程序需求)。将部分Java类放到容器共享区(例如Tomcat share lib)去加载的办法也是一个思路,但前提是容器里部署了多个应用,且这些应用有大量的共享类库
发表于 2017-08-11 22:24:59 回复(0)