本文概述
- 年轻一代
- 旧空间
- 非堆内存
- java.lang.OutOfMemoryError的原因
堆结构
文章图片
堆分为两部分(或几代):
- 年轻一代(或年轻空间或苗圃)
- 老一代(或老空间或终身制)
Java的最新发行版中有一部分内容称为Keep Area。它包含托儿所中最近分配的对象。它直到下一代才收集垃圾。
- 伊甸园:首先在这里创建所有对象。它比两个幸存者空间大。它占用了年轻一代76%的空间。当Eden充满时, 将触发次要GC。
- 幸存者空间:它是在伊甸园空间的垃圾收集中幸存下来的一组对象。从(S0)有两个幸存者空间, 称为(S1)的幸存者空间。它避免了内存碎片。关于幸存者的要点是, 两个幸存者之一始终是空的。
旧空间 它包含寿命长的对象。此过程称为旧集合。经过数轮次要GC检验后, 长寿对象得以幸存。当旧空间即将达到极限时, 将清除旧内存的主要资源。通常, 垃圾回收器会在达到其极限时在旧一代中执行。旧的垃圾收集器称为主要GC。移除对象花费的时间太长。
这里出现一个问题:“如果老一代的对象需要引用年轻一代的对象, 会发生什么?”
【Java堆解析】为了处理这种情况, JVM在旧版本中管理一个称为卡表的表。它是一个512字节的内存块。当老一代中的对象引用年轻一代中的对象时, 它将记录在卡表中。当年轻一代执行次要GC时, GC仅搜索该表。它确定它是否适用于GC, 而不是检查旧版本中所有对象的引用。写屏障管理卡表。该设备可提高次要GC的性能。
非堆内存 它包括一个在所有线程之间共享的方法区域。它存储每个类的结构。它的大小可以固定或可变。它不需要是连续的。
永久世代(PermGen)
JVM在运行时生成它。它包含JVM所需的应用程序元数据。元数据包括应用程序中使用的类和方法。它还包括Java SE库类和方法。
元空间在Java 8中替换了它。这意味着在Java 8中不会发生java.lang.OutOfMemoryError。在元空间中引入了两个新标志, 它们是:-XXMetasapceSize和?XXMaxMetaspaceSize。元空间的主要动机是, 只要类加载器处于活动状态, 元数据就在元空间中保持活动状态。
PermGen和元空间之间的主要区别是:PermGen是堆的一部分, 而元空间是本机内存的一部分。
文章图片
代码缓存:这是与堆分开的内存区域。它用于本机代码的编译和存储。这是一个固定大小的空间。如果已满, JVM将不会编译任何其他代码。为避免这种情况, 可以使用以下大小选项调整代码缓存:
- InitialCodeCacheSize:其默认大小(字节)为160K。
- ReservedCacheSize:其默认最大大小为48M。
- CodeCacheExpansionSize:其默认大小为32K或64K。
java.lang.OutOfMemoryError的原因 当应用程序尝试向堆空间区域中添加更多数据, 但没有足够的空间时, 将触发该错误。 JVM达到堆大小限制时将抛出Java堆空间错误。
- 数据量激增:这种情况是应用程序尝试将更多数据添加到堆空间中, 但没有足够的空间供其使用。
- 内存泄漏:这是一个编程错误, 导致你的应用程序连续消耗更多的内存。它可以以多种方式发生。当对象不再由应用程序使用但垃圾收集器无法识别它时, 这是一种情况。你可以使用内存管理工具(例如HP jmeter, JProbe和IBM Tivoli)来识别无用的对象和内存泄漏。
文章图片
例
public class MemoryLeaksDemo{ public static void main(String[] args){ int[] arr = new int[999999999];
//allocating memory to arraySystem.out.println("OutOfMemoryError");
} }
输出:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat MemoryLeaksDemo.main(MemoryLeaksDemo.java:5)
推荐阅读
- 《未来的夏娃》观后对安卓未来的看法
- Java反编译器
- Java ExecutorService使用线程池
- Java EE解析
- 什么是Java()
- 如何验证Java版本
- Java绝对值abs()方法
- 如何在Java中获取字符串输入
- 如何在Java中对HashMap进行排序