Jvm内存溢出

本文详细介绍了Java堆内存溢出、虚拟机栈和本地方法栈溢出、方法区和运行时常量池溢出以及本机直接内存溢出的情况。通过示例代码展示了各种溢出的触发和异常信息,并给出了相应的解决策略,包括调整JVM参数和使用内存分析工具。此外,还提及了JDK8后元空间取代永久代的相关参数设置。
摘要由CSDN通过智能技术生成

堆内存溢出

eclipse设置

-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8

run configuration设置

-verbose:gc -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError 

代码如下:

public class JvmTest {
	
	static class OOMObject{
		
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<OOMObject> list = new ArrayList<OOMObject>();
		
		while(true) {
			list.add(new OOMObject());
		}
	}

}

结果:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid10052.hprof ...
Heap dump file created [27957091 bytes in 0.078 secs]

解决方法:

使用内存映像分析工具(如:eclipse memory analyzer)对Dump出来的堆转储快照进行分析。

如果是内存泄漏,查看是哪个本应当被回收的对象没有被回收,通过工具查看GC Root引用链。

如果是内存溢出,那么就检查虚拟机堆参数设置(-Xms,-Xmx)

虚拟机栈溢出和本地方法栈溢出

HotSpot栈大小由-Xss设定(因为它不区分虚拟机栈和本地方法栈)

run configuration设置

-verbose:gc -Xss128k

代码如下:

public class JvmTest {
	
	private int stackLength = 1;
	
	
	
	public void stackLeak() {
		stackLength++;
		stackLeak();
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		JvmTest oom  = new JvmTest();
		try {
			oom.stackLeak();
		}catch (Throwable e) {
			System.out.println("stack length:" + oom.stackLength);
			throw e;
		}
		
	}

}

创建线程导致内存溢出异常

设置:

-verbose:gc -Xss2M

代码

public class JvmTest {
	
	private void dontStop() {
		while(true) {
			
		}
	}
	
	public void stackLeakByThread() {
		while(true) {
			Thread thread = new Thread(new Runnable() {

				@Override
				public void run() {
					// TODO Auto-generated method stub
					dontStop();
				}
				
			});
			thread.start();
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		JvmTest oom  = new JvmTest();
		oom.stackLeakByThread();
		
	}

}

这个代码容易让操作系统假死,因为在windows平台的虚拟机上,Java的线程直接映射到操作系统的内核线程上,无限的创建会让操作系统压力很大。

结果:

unable to create native thread

方法区和运行时常量池溢出

运行时常量池导致的内存溢出异常

设置:

-verbose:gc -XX:PermSize=6M -XX:MaxPermSize=6M -Xmx6M

代码:

public class JvmTest {
	


	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Set<String> set = new HashSet<String>();
		short i = 0;
		while(true) {
			set.add(String.valueOf(i++).intern());
		}
		
	}

}

因为jdk7或更高版本把原本存放在永久代的字符串常量池移到了java堆中所以要使用-Xmx限制最大堆。

显示异常:

[GC (Allocation Failure)  1024K->848K(5632K), 0.0019114 secs]
[GC (Allocation Failure)  1872K->1792K(5632K), 0.0048692 secs]
[GC (Allocation Failure)  2735K->2736K(5632K), 0.0027380 secs]
[GC (Allocation Failure)  3760K->3648K(5632K), 0.0030725 secs]
[Full GC (Ergonomics)  3648K->3572K(5632K), 0.2101547 secs]
[Full GC (Ergonomics)  4596K->4595K(5632K), 0.0273795 secs]
[Full GC (Ergonomics)  4921K->4918K(5632K), 0.0171513 secs]
[Full GC (Allocation Failure)  4918K->4906K(5632K), 0.0398508 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.HashMap.resize(HashMap.java:704)
    at java.util.HashMap.putVal(HashMap.java:663)
    at java.util.HashMap.put(HashMap.java:612)
    at java.util.HashSet.add(HashSet.java:220)
    at MMemory.JvmTest.main(JvmTest.java:36)
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=6M; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=6M; support was removed in 8.0

借助CGlib使方法区出现内存溢出异常

-verbose:gc -XX:PermSize=10M -XX:MaxPermSize=10M

由于书中没有给出CGlib的版本,这段代码运行问题挺多的,以后再写。

JDK8之后,元空间代替了永久代。

涉及参数:

元空间最大值

-XX:MaxMetaspaceSize

元空间初始大小

-XX:MetaspaceSize

垃圾收集之后控制最小元空间剩余容量的百分比

-XX:MinMetaspaceFreeRatio

本机直接内存溢出

参数

-verbose:gc -Xmx20M -XX:MaxDirectMemorySize=10M

书中代码使用到了Unsafe类,这个类据说是在jdk6之后被移除,我在写代码的时候,发现import失败,在网上查,说不建议用这个包。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值