/**
* 堆栈溢出错误模拟
*
* @author sunzhiqiang
* @date 2021/12/01 19:19:36
*/
public class _1_StackOverflowErrorMock {
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
try {
stackOverflowError();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
int num = 0;
while (true) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(num);
num++;
}
}).start();
new CountDownLatch(1).await();
}
private static void stackOverflowError() {
try {
TimeUnit.NANOSECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
stackOverflowError();
}
}
线程1代码抛出异常了,线程2还会运行:
——这里的栈溢出,只是一个栈帧装不下;
代码地址(3_memory):
msb-debug
Java笔记:MAT使用详解
一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)
/**
* 内存泄漏模拟
* jmap -dump:format=b,file=D:/workspace/mashibing/msb-debug/dump.hprof pid
*
* @author sunzhiqiang
* @date 2021/11/26 21:56:42
*/
@Data
public class MemoryLeakMock {
private List<Object> list = new ArrayList<>();
public static void main(String[] args) throws InterruptedException {
MemoryLeakMock memoryLeakMock = new MemoryLeakMock();
long num = 1 * 1024 * 1024;
while (num > 0) {
memoryLeakMock.getList().add(new byte[1024]);
num--;
}
new CountDownLatch(1).await();
}
}
jmap -dump:format=b,file=E:/Work_Space/Mca_Space/msb-debug/dump.hprof pid
疑惑:生成的dump.hprof文件,与课上的不一样;
课上的:
我的:没有提示MemoryLeakMock类的这条;
猜测可能跟jvm启动参数有关。
除了mat分析工具,还有jprofile工具,只不过是收费的。
/** * JVM参数 * -XX:MetaspaceSize=12m -XX:MaxMetaspaceSize=12m *
* java 8及之后的版本使用Metaspace来替代永久代,存放了以下信息: *
* 虚拟机加载的类信息 * 即时编译后的代码 *
* 模拟Metaspace空间溢出 **/ public class _3_MataspaceOOMTest { public static void main(String[] args) { new Thread(() -> { try { while (true) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(OOMTest.class); enhancer.setUseCache(false); enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> methodProxy.invoke(o, args)); enhancer.create(); } } catch (Throwable throwable) { throwable.printStackTrace(); } }).start(); new Thread(() -> { int num = 0; while (true) { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(num); num++; } }).start(); } static class OOMTest { } }
window系统未成功复现此异常,不知具体什么原因。
/** * 高并发请求服务器时,经常出现如下异常:java.lang.OutOfMemoryError:unable to create new native thread * native thread异常与对应的平台有关 *
* 导致原因: * 1 应用创建了太多线程了,一个应用进程创建多个线程,超过系统承载极限 * 2 服务器并不允许应用程序创建这么多线程,linux系统默认允许单个进程可以创建的线程数是1024个, * 应用创建超过这个数量,就会报java.lang.OutOfmemoryError:unable to create new native thread *
* 解决办法: * 1.想办法降低你应用程序创建线程的数量,分析应用是否真的需要创建这么多线程,如果不是,改代码将线程数量降到最低 * 2.对于有的应用,确实需要创建很多线程,远超过linux系统的默认1024个线程的限制,可以通过修改linux服务器配置,扩大linux默认限制 **/ public class _4_UnableCreateNewThreadDemo { public static void main(String[] args) { for (int i = 0; ; i++) { System.out.println("********i=" + i); new Thread(() -> { try { TimeUnit.SECONDS.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); } }, "" + i).start(); } } }
/** * 〈一句话功能简述〉
* 配置参数: * -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m ** 故障现象 * Exception in thread "main" java.lang.OutOfMemoryError:Direct buffer memory *
* 导致原因: * 写NIO程序经典使用ByteBuffer来读取或者写入数据,这是一种基于通道(Channel)与缓冲区(Buffer)的 I/O方式, * 可以使用native函数库直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。 * 这样能在一些场景种显著提高性能,因为避免了在Java堆和Native堆种来回复制数据。 *
* ByteBuffer.allocate(capability) 第一种方式是分配JVM堆内存, * ByteBuffer.allocateDirect(capability)第一种方式时分配OS本地内存,由于不需要内存拷贝所以速度相对较快。 *
* 但如果不断分配本地内存,对内存很少使用,那么JVM就不需要执行GC,DirectByteBuffer对象们就不会被回收。 * 这时候对内存重组,但本地内存可能已经使用光了,再次尝试分配本地内存就会出OutOfMemoryError,那程序就直接崩溃了。 **/ public class _5_DirectBufferMemoryDemo { public static void main(String[] args) { System.out.println("配置的maxDirectMemory:" + (sun.misc.VM.maxDirectMemory() / (double) 1024 / 1024) + "MB"); ByteBuffer bb = ByteBuffer.allocateDirect(6 * 1024 * 1024); } }
/** * 〈一句话功能简述〉
** JVM参数配置演示 * -Xms20m -Xmx20m -XX:+PrintGCDetails *
* GC 回收实践过程时会抛出OutOfMemoryError。过长的定义是,超过98%的时间用来做GC并且回收了不到2%的堆内存 * 连续多次GC都只会收到了不到2%的极端情况下才会抛出。假如不抛出GC overhead limit错误会发生什么情况呢? *
* 那就是GC清理的这么点内存很快会再次填满,迫使GC再次执行,这样就形成了恶性循环, * CPU使用率一直100%,而GC却没有任何成果 **/ public class _6_GCOverheadDemo { public static void main(String[] args) { int i = 0; List<String> list = new ArrayList<>(); try { while (true) { list.add(String.valueOf(++i).intern()); } } catch (Throwable e) { System.out.println("*******i:" + i); e.printStackTrace(); throw e; } } }
参考:OutOfMemoryError系列(2): GC overhead limit exceeded
java.lang.OutOfMemoryError: GC overhead limit exceeded问题分析及解决
慢sql为什么影响应用?
——占用连接数,导致资源无法释放。
慢sql的累计,最先会导致数据库服务器cpu飙高。一般数据库cpu利用率都不会超过20%。如果超过20%,一般来说,肯定是有慢sql了,监控慢sql,最方便的就是配一个慢sql日志,每天查一下;
一般情况下,内存溢出,只是异常,不会使jvm进程死掉。
rpc接口,传参-2M容量;
为什么阿里代码规范,代码不能超过80行?为什么尽量减少递归?
——因为栈没有执行完的时候,栈上所有方法不能释放。如果不释放,恰巧来了请求,内存达到一定阈值,会出发gc。
参考文章:
为什么说递归效率低?
为何java不推荐使用递归?