目录
程序计数器(寄存器)(线程私有)
作用:是记住下一条jvm指令的地址
特点:是线程私有的
不会存在内存溢出
虚拟机栈(线程私有)
虚拟机栈-每个线程线程运行需要的内存空间
栈帧:每个方法运行时需要的内存
每个线程只能有一个活动栈帧(栈顶部的栈帧)
栈(windows除外根据虚拟内存大小划分)默认大小1024k
栈内存越大越好吗
固定500mb 分配1mb栈 可运行500个线程
分配100mb栈 可运行5个线程
栈内存越大方法递归调用次数越多(并不是越大越好)
一般采用系统默认大小
方法内的局部变量线程安全吗
线程安全 栈帧里面存的局部变量 每个线程都有一份
static的时候针对多个线程是共享的 (会有线程安全问题)
线程共享,会有安全问题
线程私有,不会有安全问题
如果作为方法返回值逃离方法作用范围被别的线程访问到就不安全
栈内存溢出
栈帧过多会导致栈内存溢出(方法递归调用)
栈帧过大(大小直接超过栈内存)
本地方法栈(线程私有)
native方法在本地方法栈,为本地方法提供运行空间
堆(线程共享)
通过new创建对象会使用堆内存
特点:是线程共享的,堆中对象度需要考虑线程安全问题,有垃圾回收机制
堆内存溢出
list集合不回收一直往进里面添加则堆溢出
(outofmemoryerror:内存不足)(javaheapspace)
-Xmx8m:设置堆空间8m
堆内存诊断
1.jps工具
查看当前系统中有哪些进程
2.jmap工具
查看堆内存占用情况(只能查询某一个时刻)
3.jconsole工具
图形界面的,多功能的检测工具,可以连续监测(线程 堆 cpu都可以检测 连续监测)
4.jvisualvm工具
可视化虚拟机内容 堆转储dump功能抓取快照 看前多少个大对象
可以排查内存占用过高
方法区(线程共享)
存储了类的结构相关信息 成员方法成员变量构造器
方法区是规范
hotspot在jdk1.8之前永久代(存在于堆中)
hotspot在jdk1.8之后元空间(用的本地内存,操作系统内存)
已经不由jvm管理内存结构
内存溢出
jdk1.8:默认使用内存16G,设置元空间大小可用来检测溢出
设置元空间大小8m
-XX:MaxMetaspaceSize-8m
异常出现OutOfMemoryError:Metaspace
jdk1.6:
设置永久代大小为8m
-XX:MaxPermSize-8m
异常出现OutOfMemoryError:PermGen space
运行时常量池
常量池:就是一张表,虚拟机根据这张常量表找到要执行的类名,方法名,参数类型,字面量等信息
运行时常量池:常理池是.class文件中的,当该类被加载,他的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址
字符串常量池
变量拼接
执行到String s1="a"会将a对象放入串池中
String s2="b"
String s3="ab"(串池中)
String s4=s1+s2 (在堆中)先创建Stringbuilder对象
new StringBuilder().append("a").append("b").toString()
s3==s4//false
编译期优化(常量拼接)
String s5="a"+"b";直接在串池中找ab(已有)
s3==s5//true
java在编译器的优化 拼接结果ab确定
字符串延迟加载
执行一行代码再放入串池
串池特性
常量池中的字符串仅是符号,第一次用到时才变为对象
利用串池的机制,来避免重复创建字符串对象
字符串变量拼接的原理是StringBuilder(1.8)
字符串常量拼接的原理是编译器优化
可以使用intern方法,主动将串池中还没有的字符串对象放入串池
intern()
将字符串对象尝试放入串池,如果有则不会放入
如果没有则放入串池,会把串池中的对象返回
String s=new String("a")+new String("b");
这时串池中有"a","b",最后返回一个new String("ab")存在于堆中
string s2=s.intern();
s2=="ab"//true
这时的ab常量直接取存在于串池中的ab
串池的位置
1.6在是常量池的一部分 存在永久代中
内存不足触发永久代内存不足(PermGen space)
1.8从永久代放入堆中(不存在于常量池中) 优化了回收效率
内存不足触发堆内存不足(GC overhead limit exceeded)(heap space)
串池垃圾回收
无引用的minerGC
StringTable性能调优
存取大量字符串
调整-XX-StringTableSize=桶个数
考虑将字符串是否入池
直接内存
常见于nio操作,用于数据缓冲区
分配回收成本较高,但读写性能高
不收jvm内存回收管理
加入直接内存
少了一次缓冲区复制操作
内存溢出
(out of memery error)direct buffer memory
释放原理
通过Unsafe类(不属于java内存)