JVM三大性能调优参数 -Xms -Xmx -XSS的含义

  • -Xss:规定了每个线程虚拟机栈(堆栈)的大小
    • 此配置影响并发线程数大小
  • -Xms:堆的初始值
  • -Xmx:堆能达到的最大值

Java内存模型中堆和栈的区别——内存分配策略

存储方案:

  • 静态存储:编译时确定每个数据目标在运行时的存储空间需求

  • 栈式存储:数据区需求在编译时未知,运行时模块入口前确定

  • 堆式存储:编译或运行时模块入口都无法确定,动态分配。

堆和栈的联系

引用对象、数组时,栈里定义变量保存堆中目标的首地址

截屏2021-01-14 下午11.44.52

区别

  • 管理方式:栈自动释放,堆需要GC
  • 空间大小:栈比堆小
  • 碎片相关:栈产生的碎片远小于堆
  • 分配方式:栈支持静态和动态分配,堆只支持动态分配
  • 效率:栈的效率高

元空间、堆、线程独占部分间的联系——内存角度

示例如下:

截屏2021-01-14 下午11.55.25 截屏2021-01-14 下午11.55.49
  • 元空间:
    • 保存装载进来的HelloWorld对象的信息及其Method和Field。
    • 额外还有System这个类对象及该类中的成员变量和方法等
  • 堆:
  • 存储HelloWorld类创建出来的对象实例object,以及String实例“test”
  • 线程独占:
    • 当程序执行时,main线程会分配对应的虚拟机栈,本地栈以及程序计数器
    • 栈里面存有String类型的引用参数,本地变量hw,局部变量a,以及系统自带的lineNo(行号)

不同JDK版本之间的intern()方法的区别——JDK6 VS JDK6+

1
2
String s = new String("a");
s.intern();
  • JDK6:当调用intern()方法时,如果字符串常量池已创建出该字符串的对象,则返回池中该字符串的引用,否则,将此字符串对象添加到字符串常量池中,并返回该对象的引用。
  • JDK6+:当调用intern()方法时,如果字符串常量池已创建出该字符串的对象,则返回池中该字符串的引用,否则,如果该字符串对象已经存在于JAVA堆中,则将堆中此对象的引用再添加到字符串常量池中,并返回引用,如果堆中不存在,则在池中创建该字符串并返回引用。
  • 在代码中,直接引号出来的字符串会放到字符串常量池,new出来的会放到堆中

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
public class InternDiff{
public static void main(String[] args){
String s = new String("a");
s.intern();
String s2 = "a";
System.out.println(s == s2);

String s3 = new String("a") + new String("a");
s3.intern();
String s4 = "aa";
System.out.println(s3 == s4);
}
}

JDK6时:输出结果 false false

截屏2021-01-15 上午11.51.39
  • s intern时,想将堆中的字符串放到常量池中,但是常量池中已有,故放不进去,s,s1是两个不同的引用
  • S2 intern成功了,常量池中放的堆中的副本,但是只是把复制品放进去了,二者仍然不是同一个引用。

JDK6+时:输出 false true

截屏2021-01-15 上午11.57.54
  • 第一个比较和上面相同,先在常量池放了“a“,然后又在堆中创建了对象,此时intern不进去,故两个是不同的引用
  • 第二个不同,JDK7及以上,可以将引用放到常量池中,故先创建对象,然后把引用放到常量池中,所以两个是同一个引用。