JVM的内存结构、内存溢出、内存泄漏、内存模型你知道吗?

Java8后,内存分成如下几部分:程序计数器PC Register,Metaspace,Stack,Heap,和本地方法栈。

Metaspace用于存放类的元信息以及方法信息;而常量池和静态变量存在Heap中。Heap里面存储运行时产生的对象。Stack里面存放线程相关的数据,如局部变量,参数,对象引用等。PC Register存放的是当前线程执行的指令地址。本地方法栈是调用本地方法时用到的。

上图左边的Metaspace和Heap在JVM中是唯一的,全部线程都会共享这两片区域。右边的Stack/本地方法stack/程序计数器则是线程相关的。

从物理内存来讲,Metaspace不再使用虚拟机的内存,而是直接使用本地内存,由操作系统管理,仅受本地内存大小限制。
调整Metaspace内存大小的参数 

-XX:MetaspaceSize -XX:MaxMetaspaceSize

堆区Heap:
(1)存储的全部是对象。
(2)存放的这些对象是程序运行时动态创建的。
(3)jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身。
(4)常量池和静态变量存在Heap中。
栈区Stack:
(1)每个线程包含一个栈区,栈中只保存基础数据类型的对象和动态创建的对象的引用(对象本身都存放在堆区中)。
(2)每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
(3)由编译器自动分配释放,存放函数的参数值,局部变量的值等.

2、JVM内存溢出

内存溢出是指程序申请内存时,没有足够的内存供申请者使用。原因可能是:
A,数据加载过多,如一次从外部获取过多数据  
B,集合类中有对对象的引用,用完后没有清空或者集合对象未置空导致无法回收
C,循环中产生过多重复对象
D,启动参数内存值设定的过小。

解决的方法:修改JVM启动参数,加内存(-Xms,-Xmx);错误日志,是否还有其他错误;代码走查

3、JVM内存泄露

内存泄漏是指程序申请并使用内存后一直不释放,内存一直占用着。一次泄露不会有明显影响,累积泄露会导致OOM(内存溢出)。典型的现象就是系统频繁FullGC,直到最后OOM(Out of Memory)。
排查方法:使用各种profiling工具进行排查,如VisualVM,JProfiler等。可以先用jmap查看那些对象占用了大量内存,然后用btrace定位程序代码。
内存泄漏是由于代码不善引起的,要注意程序一些容易犯错的地方:
对不再使用的对象要置为null,尽早释放无用对象的引用;
程序避免用String拼接,用StringBuffer,因为每个String会占用内存一块区域;
尽量少用静态变量(全局不会回收);
及时关闭资源,在finally里面释放,或者用try-with-resources自动关闭;
定义新类时,没有重写equals()和hashCode()方法,导致隐患;
不当使用ThreadLocal造成的内存泄漏,应该在不再使用ThreadLocals时remove();
另外,服务器session时间设置过长也可能会引起内存泄漏。

2、Java内存模型

       java内存模型(Java Memory Model,JMM)java虚拟机规范定义的,用来屏蔽掉java程序在各种不同的硬件和操作系统对内存的访问的差异,从而实现java程序在各种不同的平台上都能达到内存访问的一致性。
Java内存模型的主要目标是定义程序中变量的访问规则。可以简单的认为主内存是java虚拟机内存区域中的堆,局部变量和方法参数是在虚拟机栈中定义的。但是在堆中的变量如果在多线程中都使用,就涉及到了堆和不同虚拟机栈中变量的值的一致性问题了。
虚拟机规定,线程对主内存变量的修改必须在线程的工作内存中进行,不能直接读写主内存中的变量。不同的线程之间也不能相互访问对方的工作内存。如果线程之间需要传递变量的值,必须通过主内存来作为中介进行传递。

java内存中线程的工作内存和主内存的交互是由java虚拟机定义了8种原子操作来完成的:lock unlock read load use assign store write。对于这8种操作,虚拟机也规定了一系列规则,在执行操作的时候必须遵循

微信扫描下方二维码(新开通的个人微信公众号)  更多优质资源面试文章及时获取 请大家多多支持哦

猜你喜欢

转载自blog.csdn.net/lihua5419/article/details/103630105