一般Java程序中堆内存是空间最大的一块内存区域。创建出来的对象都存在于堆上
栈上的局部变量表中,可以存放堆上对象的引用。静态变量也可以存放堆对象的引用,通过静态变量就可以实现对象在线程之间共享
堆空间有三个需要关注的值,used total max
used:当前已使用的堆内存
total:java虚拟机已经分配的可用堆内存,max是java虚拟机可以分配的最大堆内存
随着堆中的对象增多,当total内存不足时,java虚拟机会继续分配内存给堆。如果堆内存不足,java虚拟机就会不断的分配内存,total值会变大。total最多只能与max相等。
如果不设置任何的虚拟机参数,max默认是系统内存的1/4,total默认是系统内存的1/64。在实际应用中一般都需要设置total和max的值
package JVM.heap;
import java.io.IOException;
import java.util.ArrayList;
/**
* 堆内存的使用和回收
*/
public class Demo1 {
public static void main(String[] args) throws InterruptedException, IOException {
ArrayList<Object> objects = new ArrayList<Object>();
while (true){
objects.add(new byte[1024 * 1024 * 100]);
}
}
}
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Memory used total max usage GC
heap 185M 972M 14409M 1.29% gc.ps_scavenge.count 0
ps_eden_space 185M 254M 5319M 3.49% gc.ps_scavenge.time(ms) 0
ps_survivor_space 0K 43008K 43008K 0.00% gc.ps_marksweep.count 0
ps_old_gen 0K 692224K 11066368K 0.00% gc.ps_marksweep.time(ms) 0
nonheap 29M 30M -1 96.51%
code_cache 7M 8M 240M 3.31%
metaspace 19M 20M -1 96.90%
compressed_class_space 2M 2M 1024M 0.23%
direct 1500M 1500M - 100.00%
mapped 0K 0K - 0.00%
修改堆的大小,可以使用虚拟机参数 –Xmx(max最大值)和-Xms (初始的total)
语法:-Xmx值 -Xms值
单位:字节(默认,必须是 1024 的倍数)、k或者K(KB)、m或者M(MB)、g或者G(GB)
限制:Xmx必须大于 2 MB,Xms必须大于1MB
arthas中显示的heap堆大小与设置的值不一样的解释:arthas中的heap堆内存使用了JMX技术中内存获取方式,这种方式与垃圾回收器有关,计算的是可以分配对象的内存,而不是整个内存。
Java服务端程序开发时,建议将-Xmx和-Xms设置为相同的值,在程序启动之后可使用的总内存就是最大内存,而无需向java虚拟机再次申请,减少申请并分配内存时间上的开销,同时也避免出现内存过剩之后堆收缩的情况。
方法区存储每个类的基本信息(元信息),一般称之为InstanceKlass对象,在类的加载阶段完成。
方法区还存放运行时常量池,常量池中存放的是字节码中的常量池内容。
方法区中还有一块区域叫字符串常量池(StringTable)。字符串常量池存储在代码中定义的常量字符串内容。比如“123” ,123就会被放入字符串常量池
memory
命令打印出内存情况,JDK7及之前的版本查看ps_perm_gen属性,JDK8及之后的版本查看metaspace属性。import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Opcodes;
import java.io.IOException;
/**
* 方法区的溢出测试
*/
public class Demo1 extends ClassLoader {
public static void main(String[] args) throws IOException {
System.in.read();
Demo1 demo1 = new Demo1();
int count = 0;
while (true) {
String name = "Class" + count;
ClassWriter classWriter = new ClassWriter(0);
classWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, name, null
, "java/lang/Object", null);
byte[] bytes = classWriter.toByteArray();
demo1.defineClass(name, bytes, 0, bytes.length);
System.out.println(++count);
}
}
}
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
-XX:MaxPermSize=值来控制
-XX:MaxMetaspaceSize=值
将元空间最大大小进行限制-XX:MaxMetaspaceSize=128M
192546
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at JVM.methodarea.Demo1.main(Demo1.java:21)
public static void main(String[] args) {
String a = "1";
String b = "2";
String c = "12";
String d = a + b;
System.out.println(c == d); //false
}
public static void main(String[] args) {
String a = "1";
String b = "2";
String c = "12";
String d = "1" + "2";
System.out.println(c == d); //true
}
public static void main(String[] args) {
String s1 = new StringBuilder().append("think").append("123").toString();
System.out.println(s1.intern()==s1);
// java是在启动的过程中,直接放到字符串常量池中
String s2 = new StringBuilder().append("ja").append("va").toString();
System.out.println(s2.intern()==s2);
}
- JDK6版本中intern () 方法会把第一次遇到的字符串实例复制到永久代的字符串常量池中,返回的也是永久代里面这个字符串实例的引用。JVM启动时就会把java加入到常量池中。
- JDK7及之后版本中由于字符串常量池在堆上,所以intern () 方法会把第一次遇到的字符串的引
用放入字符串常量池。
ByteBuffer
Memory used total max usage GC
heap 185M 972M 14409M 1.29% gc.ps_scavenge.count 0
direct 1500M 1500M - 100.00%
mapped 0K 0K - 0.00%
-XX:MaxDirectMemorySize=大小
-XX:MaxDirectMemorySize=1m
/**
* 直接内存的使用和回收
*/
public class Demo1 {
public static int size = 1024 * 1024 * 100; //100mb
public static List<ByteBuffer> list = new ArrayList<ByteBuffer>();
public static int count = 0;
public static void main(String[] args) throws IOException, InterruptedException {
System.in.read();
while (true) {
//1.创建DirectByteBuffer对象并返回
//2.在DirectByteBuffer构造方法中,向操作系统申请直接内存空间
ByteBuffer directBuffer = ByteBuffer.allocateDirect(size);
//directBuffer = null;
list.add(directBuffer);
System.out.println(++count);
Thread.sleep(5000);
}
}
}
Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory