jvm堆内存和非堆内存(小白入门文,各博客视频基础总结)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jvm堆内存和非堆内存(小白入门文,各博客视频基础总结)相关的知识,希望对你有一定的参考价值。
参考技术A 一:堆内存和非堆内存定义
Java虚拟机具有一个堆(Heap),堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是Java虚拟机启动时创建的。在JVM中堆之外的内u你成为非堆内存(Non-heap memory)。
堆内存以及相应垃圾回收算法
1.堆的大小可以固定,也可以扩大和缩小,堆内存不需要是连续空间。
2.对象创建后进入Eden。年轻代分为Eden和Survivor。Survivor由FromSpace和ToSpace组成。Eden区占大容量,Survivor占小容量,默认比例8:1:1。
MinorGC:采用复制算法。首先把Eden和ServivorFrom区域中存活的对象赋值到ServivorTo区域(如果对象年龄达到老年标准/ServivorTo位置不够了,则复制到老年代),同时对象年龄+1,然后清空Eden和ServivorFrom中的对象。然后ServivorTo和ServivorFrom互换。
3.老年代
老年代存放生命周期长的内存对象。
老年代对象相对稳定,所以不会频繁GC。在进行MajorGC前一般都先进行一次MinorGC,使新生代的对象进入老年代,导致空间不够用时才触发。当无法找到足够大的连续空间分配给新晋的对象也会提前触发MajorGC进行垃圾回收。
MajorGC:如果使用CMS收集器,采用标记-清除算法。首先扫描老年代,标记所有可回收对象,标记完成后统一回收所有被标记对象。同时会产生不连续的内存碎片。碎片过多会导致以后程序运行需要分配较大对象时,无法找到足够的连续内存,而不得已再次出发GC。否则采用标记-压缩算法。
标记-压缩:在标记可回收对象后,将不可回收对象移向一端,然后清除标记对象。
当老年代也满了装不下时,抛出OOM异常。
二:永久代
内存中永久保存的区域,主要存放Class和Meta(元数据)的信息,Class在被加载的时候被放入永久区域。他和存放实例的区域不同,GC不会再主程序运行期对永久区进行清理。所以也可可能导致永久代区域随着加载Class的增多而胀满,抛出OOM。
Java8中,永久代已经被移除,被一个成为“元数据区”(元空间)的区域所取代。
元空间的本质与永久代类似,都是JVM方法区的实现。不过元空间使用本地内存,永久代在JVM虚拟机中。因此,默认情况下,元空间的大小受本地内存限制。类的元数据放入native memory,字符串常量池和类的静态变量放入java堆中,这样可以加载多少类的元数据就不再由MaxPermSize控制,而是由系统实际可用空间控制。
1元空间解决了永久代的OOM问题,元数据和class对象在永久代容易出现性能问题和内存溢出。
2类的方法信息等比较难确定其大小,对于永久代的大小指定比较困难,小永久代溢出,大老年代溢出。
3永久代会为GC带来不必要的复杂度,回收效率低。
三:堆内存参数调优
1.-Xms 设置初始分配内存大小,默认物理内存1/64
2.-Xmx 设置最大分配内存,默认物理内存1/4
long maxMemory = Runtime.getRuntime().maxMemory(); long totalMemory = Runtime.getRuntime().totalMemory(); System.out.println("最大分配内存"+maxMemory/(double)1024/1024+"MB "+maxMemory/(double)1024/1024/1024+"GB"); System.out.println("默认分配内存"+totalMemory/(double)1024/1024+"MB "+totalMemory/(double)1024/1024/1024+"GB");
JVM中的堆和非堆内存
JVM内存包含以下部分:
- 堆内存,它是Java对象的存储
- 非堆内存,Java用于存储加载的类和其他元数据
- 其他,JVM代码本身,JVM内部结构,加载的探查器代理代码和数据等。
堆
JVM有一个堆,它是运行时数据区,从中分配所有类实例和数组的内存。它是在JVM启动时创建的。
可以使用以下VM选项配置堆大小:
1 2 |
|
默认情况下,最大堆大小为64 Mb。
对象的堆内存由自动内存管理系统回收,该系统称为垃圾收集器。堆可以是固定大小,也可以扩展和缩小,具体取决于垃圾收集器的策略。
非堆
此外,JVM还有堆以外的内存,称为非堆内存。它在JVM启动时创建并存储每类结构,例如运行时常量池,字段和方法数据,方法和构造函数的代码,以及实习字符串。
不幸的是,JVM在非堆内存上提供的唯一信息是它的整体大小。没有关于非堆内存内容的详细信息。
非堆内存大小的异常增长可能表示存在潜在问题,在这种情况下,您可以检查以下内容:
- 如果存在类加载问题,例如泄漏的加载器。
- 如果有字符串被大量实施。为了检测这种问题,可以使用对象分配记录。
如果应用程序确实需要大量非堆内存且默认最大大小为64 Mb是不够的,则可以借助-XX:MaxPermSize
VM选项扩大最大大小。例如,-XX:MaxPermSize=128m
设置128 Mb的大小。
堆栈和堆之间的异同
Similarities and Differences Between Stack and Heap
两者都是Java分配内存的方式,两者都存储在RAM中。但是,为了使事情更容易记住,堆用于动态内存分配,而堆栈用于静态分配。
它存放在哪里? 在堆栈上分配的变量可以直接从内存访问,因此,这些变量可以非常快速地运行。另一方面,访问堆上的对象需要更多时间。
分配何时发生? 在堆栈上,编译程序时会发生内存分配。同时,在堆上,它在程序运行时开始。
既然如此,那么在编译之前,如果要使用堆栈,则需要知道需要多少数据和内存。堆栈的另一个限制是它无法处理需要大量内存的大块变量。如果您不知道在运行时需要多少数据,或者您需要大量数据的内存,那么您需要使用堆。
简而言之…
堆栈stack
- 堆栈的大小将随着方法和函数根据需要创建和删除局部变量而变化。
- 分配内存然后随后释放,而无需管理内存分配。
- 堆栈的大小限制,可能会根据您使用的操作系统而有所不同。
- 只要创建它们的函数正在运行,就会存在存储在堆栈中的变量。
堆heap
- 内存不是自动管理的,也不是由管理堆栈的方式由中央处理单元严格管理的。当不再需要这些块时,您需要自己释放已分配的内存。
- 堆很容易发生内存泄漏,其中内存被分配给未使用的对象,并且除此之外的进程将无法使用。
- 堆中没有大小限制。
- 与堆栈相比,堆中的对象访问速度要慢得多。写入堆上的内存也比较慢。
堆栈使用起来更容易,更快,但它带来了很多限制,如果你使用堆,你可以忽略它们。
你什么时候使用堆栈? 堆栈只能用于占用少量内存的局部变量。好消息是内存分配和管理不会成为您的问题,访问这些对象的速度非常快。它确实受到大小限制以及无法在堆栈上调整变量的事实。
你什么时候使用堆?如果存在需要全局访问的变量,则使用堆来分配内存,而不是只对创建它的方法和函数可用。当你需要大量内存时,堆也很好,因为它对内存大小没有限制。您还可以在堆上调整变量的大小。
以上是关于jvm堆内存和非堆内存(小白入门文,各博客视频基础总结)的主要内容,如果未能解决你的问题,请参考以下文章