4. Java堆
4.1 定义
- 通过new关键字都会使用堆内存
特点
- 它是线程共享的, 堆中对象都需要考虑线程安全的问题
- 有垃圾回收机制
4.2 堆内存溢出
public class Demo_1 {
public static void main(String[] args) {
int i=0;
try{
List<String> list=new ArrayList<>();
String a="hello";
while (true){
list.add(a);//指数叠加
a=a+a;
i++;
}
}catch (Throwable e){
e.printStackTrace();
System.out.println(i);
}
}
}
运行这段代码可以发现报 java.lang.OutOfMemoryError: Java heap space这个错误
这就是堆内存溢出.
4.3 堆内存诊断
- jps工具
- 查看当前系统中有哪些java进程
- jmap工具
- 查看堆内存占用情况, jmap - heap进程id
- jconsole工具
- 图形界面的, 多功能的监测工具, 可以连续监测
- jvisualvm工具
下载地址: https://visualvm.github.io/download.html
5. 方法区(Method Area)
5.1 定义
方法区(Method Area)与Java堆一样, 是各个线程共享的内存区域, 它用于存储已被虚拟机加载的类型信息, 常量, 静态变量, 即时编译后的代码缓存等数据.
5.2 组成
5.3 方法区内存溢出
-
1.8以前会导致永久代内存溢出
java.lang.OutOfMemoryError: PermGen space
-
1.8之后会导致元空间内存溢出
java.lang.OutOfMemoryError: Metaspace
5.4 运行时常量池
运行时常量池(Runtime Constant Pool)是方法区的一部分.Class文件中除了有类的版本, 字段, 方法, 接口等信息外, 还有一项是常量池(Constant Pool Table) ,用于存放编译期生成的各种字面量与符号引用, 这部分内容将在加载后存放到方法区的运行时常量池中.
5.5 StringTable
public class Demo_3 {
public static void main(String[] args) {
// StringTable["a","b","ab"]
/**
* 首先StringTable中存入s1和s2的字符串
*
*/
String s1="a";
String s2="b";
String s3="ab";//s3 new StringBuilder.append("a").append("b").toString()
// 新创建一个new String("ab")在堆中
String s4=s1+s2;//s4去常量池中器去拿, 创建的ab存入StringTable
System.out.println(s3==s4);//false
String s5="ab";
System.out.println(s3==s5);//true
String s6=s4.intern();
System.out.println(s3==s6);//true
}
}