JVM内存概念
共享内存区域
堆:
存储new出来的实例化对象,大多数情况实例化对象会存放在Eden区,当eden区满了之后字节码执行引擎会使用minor gc进行垃圾回收(用gc root寻址法等)。
方法区(元空间/永久带):使用的是物理内存,存放全局的常量,静态变量,类信息(对象在堆中,方法区中存的依旧是指针)
线程独占内存区域
栈(FILO):先入后出结构
栈帧:每一个方法会开辟一个栈帧存储方法内用到的局部变量、操作数栈、动态链接、方法出口。
- 局部变量:仅方法内部使用的变量
main方法中如果有new对象,局部变量表中的对象为对象在堆中的地址,类似于指针。
- 操作数栈:存储当前操作的变量,E.x 1+2=3,会将1和2分别压入操作数栈然后将1和2出栈在CPU缓存中进行加法计算,返回结果3重新压入到操作数栈,最后将操作数栈中的结果拿出进行赋值,操作数栈则清空
- 动态链接:存放程序中调用的非静态方法的内存区位置。E.x user.login() 如果login是非静态方法,则该线程的栈帧中存储的动态链接则是login()在方法区(元空间)中对应的内存地址。
- 方法出口:方法执行结束后返回的上层方法的位置信息
E.x
user.login(){//方法体}
执行结束后返回调用login()方法的位置继续向下执行。
本地方法栈:存放native修饰的方法,由C、C++等语言实现的底层dll文件中的方法,可以实现java语言调用c++等其他语言写的本地方法
程序计数器:每一个线程独有的内存空间,用来存储下一条运行代码的位置标识例如汇编代码4:iLoad_1,其中4即为位置标识,每执行完一行代码进行更新。
多线程执行时用来记录当前线程执行的位置,切换回来时在当前位置继续执行。
内存分配:
指针碰撞分配方式:内存依序存储,每次指针向后移动对象大小的空间,指向下一个对象存储的位置
空闲列表分配方式:可能由于GC等问题,内存中的对象不是依序排列,其中有空缺的内存空间,该部分空间会以列表方式进行村存储,后面的对象在列表中找到对应的空闲存储空间进行使用
多线程内存争抢问题解决方案:CAS 比较并替换-默认、TLAB(thread local allocation buffer) 线程本地缓存 -XX:+/-UseTLAB 参数设置本地缓存大小。
内存调优:
windows下可以使用jdk自动监控程序:jvisualvm查看内存中各个区域的情况
调优目的:由于GC会触发STW机制,所以要尽量减少GC,可以适当调整内存的大小分配,如下图
方法区如果不设置值,该空间初始大小21M,会自动根据GC回收情况进行自动扩容,否则会导致频繁的full GC降低性能
-Xss 栈默认大小为1M,该配置设置的值是针对单个线程设置的栈空间大小,该值越小,单个线程可以调用的方法越少,但可以开启的线程总量会变多。
STW目的:避免检测垃圾对象时,对象的状态发生变更,产生对象的错误清理。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。