JVM--内存管理

2019-08-20  本文已影响0人  风吹过那天

JVM运行时内存数据区域

前言

JVM会在执行过程中把它所管理的内存花费为若干个不同的数据区域。如下图所示

jvm内存管理模型.jpg

下面分别对这些区域进行解释。


1、程序技术器

2、Java虚拟机栈

3、本地方法栈

4、Java堆

堆内存.jpg
-Xms   JVM启动时申请的最小堆内存,默认为物理内存的1/64但小于1G  

-Xmx   JVM启动时申请的最大堆内存,默认为物理内存但1/4但小于1G

-XX:MinHeapFreeRadio  默认当剩余堆内存空间小于40%时,JVM会将-Xms会增大到-Xmx的大小,通过该参数可以指定这个比例

-XX:MaxHeapFreeRadio  默认当空余堆内存大于70%时,JVM会减小堆内存至-Xms大小,通过该参数可以指定这个比例

5、方法区

6、运行时常量池

7、直接内存

直接内存并不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域,但是这部分内存也会被频繁调用,而且可能导致OutOfMemoryError异常。

在NIO类中引入了基于Channel与Buffer的I/O方式,其可以使用Native函数库直接分配堆外内存。然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作,这样避免了在Java堆与Native堆中来回复制数据。

直接内存的分配不会受到Java堆大小的限制,但是内存一定会受到本机总内存大小以及处理器寻址空间的限制。千万不要在设置-Xmx时忽略直接内存,从而使得各个内存区域总和大于物理内存限制,导致在进行动态扩展时出现OutOfMemoryError异常


对象探秘

对象的创建

虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用是否已经被加载、解析和初始化过。若没有则先执行类加载过程。在类加载通过后,虚拟机将为新生对象分配内存,相当于是从Java堆中划出来一部分。目前有两种分配方法。

Java堆是否规整,取决于垃圾收集器是否带有压缩整理功能决定的。因此在使用Serial,ParNew等带Compact过程的收集器时,采用的分配算法是指针碰撞,而使用CMS这种基于Mark-Sweep算法的收集器时,通常采用的是空闲列表。

由于修改指针所指向的内存地址在并发情况下,不是线程安全的。目前有两种方案解决这个问题。

内存分配完成后,虚拟机将内存空间初始化为0,然后对对象进行必要的设置,设置信息存放在对象头。最后调用init方法得到一个可用的对象。

对象的内存布局

对象在内存中存储的布局可以分为3块区域:对象头,实例数据和对齐填充。

对象头

对象头信息分为两部分.

存储内容 标志位 状态
对象哈希码,对象分代年龄 01 未锁定
指向锁记录的指针 00 轻量级锁定
指向重量级锁的指针 10 膨胀(重量级锁定)
空,不需要记录信息 11 GC标记
偏向线程ID,偏向时间戳,对象分代年龄 01 可偏向

对象的访问定位

Java程序需要通过栈上的reference数据来操作堆上的具体对象。目前主流的访问方式有使用句柄和直接指针两种。

上一篇 下一篇

猜你喜欢

热点阅读