久久性网

你的位置:国内精品久久久久久tv > 久久性网 > 人人视频综合网就类似于将 XXXL 号的对象

人人视频综合网就类似于将 XXXL 号的对象

发布日期:2022-06-13 16:38    点击次数:191
人人视频综合网在《Java造谣机程序》的法规里,除了要津计数器外,造谣机内存的其他几个运行时区域都有发生 OutOfMemoryError 特地的可能。 本篇主要包括如下 OOM 的先容和示例: java.lang.Stac...

 人人视频综合网在《Java造谣机程序》的法规里,除了要津计数器外,造谣机内存的其他几个运行时区域都有发生 OutOfMemoryError 特地的可能。

本篇主要包括如下 OOM 的先容和示例:

java.lang.StackOverflowError java.lang.OutOfMemoryError: Java heap space java.lang.OutOfMemoryError: GC overhead limit exceeded java.lang.OutOfMemoryError-->Metaspace java.lang.OutOfMemoryError: Direct buffer memory java.lang.OutOfMemoryError: unable to create new native thread java.lang.OutOfMemoryError:Metaspace java.lang.OutOfMemoryError: Requested array size exceeds VM limit java.lang.OutOfMemoryError: Out of swap space java.lang.OutOfMemoryError:Kill process or sacrifice child

咱们常说的 OOM 特地,其实是 Error

一. StackOverflowError

1.1 写个 bug

public class StackOverflowErrorDemo {      public static void main(String[] args) {         javaKeeper();     }      private static void javaKeeper() {         javaKeeper();     } } 

JVM 造谣机栈是有深度的,在践诺顺序的时候会伴跟着入栈和出栈,上边的顺序不错看到,main 顺序践诺后束缚的递归,朝夕把栈撑爆了

Exception in thread "main" java.lang.StackOverflowError  at oom.StackOverflowErrorDemo.javaKeeper(StackOverflowErrorDemo.java:15) 

1.2 原因分析

无穷递归轮回调用(最常原宥因),要时期持重代码中是否有了轮回调用顺序而无法退出的情况 践诺了无边顺序,导致线程栈空间耗尽 顺序内声明了海量的局部变量 native 代码有栈上分拨的逻辑,何况条目的内存还不小,比如 java.net.SocketInputStream.read0 会在栈上条目分拨一个 64KB 的缓存(64位 Linux)

1.3 处置决策

建立激励无穷递归调用的特地代码, 通过要津抛出的特地堆栈,找出连接肖似的代码行,生搬硬套,建立无穷递归 Bug 排查是否存在类之间的轮回依赖(当两个对象相互援用,在调用toString顺序时也会产生这个特地) 通过 JVM 启动参数 -Xss 加多线程栈内存空间, 某些正常使用场景需要践诺无边顺序或包含无边局部变量,这时不错顺应地普及线程栈空间纵容

二. Java heap space

Java 堆用于存储对象实例,咱们只有连接的创建对象,何况保证 GC Roots 到对象之间有可达旅途来幸免 GC 撤废这些对象,那跟着对象数量的加多,总容量波及堆的最大容量纵容后就会产生内存溢出特地。

Java 堆内存的 OOM 特地是本色应用中最常见的内存溢出特地。

2.1 写个 bug

/**  * JVM参数:-Xmx12m  */ public class JavaHeapSpaceDemo {      static final int SIZE = 2 * 1024 * 1024;      public static void main(String[] a) {         int[] i = new int[SIZE];     } } 

代码试图分拨容量为 2M 的 int 数组,要是指定启动参数 -Xmx12m,分拨内存就不够用,就类似于将 XXXL 号的对象,往 S 号的 Java heap space 里面塞。

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space  at oom.JavaHeapSpaceDemo.main(JavaHeapSpaceDemo.java:13) 

2.2 原因分析

请求创建一个超大对象,平日是一个大数组 超出预期的拜谒量/数据量,平日是上游系统请求流量飙升,常见于各类促销/秒杀行径,不错相聚业务流量宗旨排查是否有尖状峰值 过度使用消除器(Finalizer),该对象莫得立即被 GC 内存流露(Memory Leak),无边对象援用莫得开释,JVM 无法对其自动回收,常见于使用了 File 等资源莫得回收

2.3 处置决策

针对大部分情况,平日只需要通过 -Xmx 参数调高 JVM 堆内存空间即可。要是仍然莫得处置,不错参考以下情况做进一步处理:

要是是超大对象,不错查验其合感性,比如是否一次性查询了数据库一道终端,而莫得做终端数纵容 要是是业务峰值压力,不错谈判添加机器资源,大要做限流左迁。 要是是内存流露,需要找到持有的对象,修改代码筹办,比如关闭莫得开释的团结

口试官:说说内存表现和内存溢出

加送个常识点,三连的终将成为大神~~

内存表现和内存溢出

内存溢出(out of memory),是指要津在肯求内存时,莫得满盈的内存空间供其使用,出现out of memory;比如肯求了一个 Integer,但给它存了 Long 身手存下的数,那即是内存溢出。

内存表现( memory leak),是指要津在肯求内存后,无法开释已肯求的内存空间,一次内存表现危害不错忽略,但内存表现堆积后果很严重,岂论几许内存,朝夕会被占光。

memory leak 最终会导致 out of memory!

三、GC overhead limit exceeded

JVM 内置了垃圾回收机制GC,是以算作 Javaer 的咱们不需要手工编写代码来进行内存分拨和开释,但是当 Java 程度耗尽 98% 以上的时辰践诺 GC,但只归附了不到 2% 的内存,且该动作连气儿肖似了 5 次,就会抛出 java.lang.OutOfMemoryError:GC overhead limit exceeded 空虚(俗称:垃圾回收上面)。浅显地说,即是应用要津仍是基本耗尽了扫数可用内存, GC 也无法回收。

假如不抛出 GC overhead limit exceeded 空虚,那 GC 清算的那么一丢丢内存很快就会被再次填满,迫使 GC 再次践诺,这样恶性轮回,CPU 使用率 100%,而 GC 没什么后果。

3.1 写个 bug

出现这个空虚的实例,其实咱们写个无穷轮回,往 List 或 Map 加数据就会一直 Full GC,直到扛不住,这里用一个贬抑易发现的栗子。咱们往 map 中添加 1000 个元素。

/**  * JVM 参数: -Xmx14m -XX:+PrintGCDetails  */ public class KeylessEntry {      static class Key {         Integer id;          Key(Integer id) {             this.id = id;         }          @Override         public int hashCode() {             return id.hashCode();         }     }      public static void main(String[] args) {         Map m = new HashMap();         while (true){             for (int i = 0; i < 1000; i++){                 if (!m.containsKey(new Key(i))){                     m.put(new Key(i), "Number:" + i);                 }             }             System.out.println("m.size()=" + m.size());         }     } } 
... m.size()=54000 m.size()=55000 m.size()=56000 Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded 

从输出终端不错看到,咱们的纵容 1000 条数据莫得起作用,map 容量远出奇了 1000,而且临了也出现了咱们想要的空虚,这是因为类 Key 只重写了 hashCode() 顺序,却莫得重写 equals() 顺序,咱们在使用 containsKey() 顺序其实就出现了问题,于是就会一直往 HashMap 中添加 Key,直至 GC 都清算不掉。

 口试官又来了:说一下HashMap旨趣以及为什么需要同期竣事equals和hashcode

践诺这个要津的最终空虚,和 JVM 成立也会相联系,要是竖立的堆内存相当小,会平直报 Java heap space。算是被这个空虚截胡了,是以未必,在资源受限的情况下,无法准确瞻望要津会死于哪种具体的原因。

3.2 处置决策

添加 JVM 参数-XX:-UseGCOverheadLimit 不保举这样干,莫得着实处置问题,仅仅将特地推迟 查验神气中是否有无边的死轮回或有使用大内存的代码,优化代码 dump内存分析,查验是否存在内存表现,要是莫得,加大内存

四、Direct buffer memory

咱们使用 NIO 的时候往往需要使用 ByteBuffer 来读取或写入数据,这是一种基于 Channel(通道) 和 Buffer(缓冲区)的 I/O 面貌,它不错使用 Native 函数库平直分拨堆外内存,然后通过一个存储在 Java 堆里面的 DirectByteBuffer 对象算作这块内存的援用进行操作。这样在一些场景就幸免了 Java 堆和 Native 中来往话制数据,久久性网是以性能会有所普及。

Java 允许应用要津通过 Direct ByteBuffer 平直拜谒堆外内存,许多高性能要津通过 Direct ByteBuffer 相聚内存映射文献(Memory Mapped File)竣事高速 IO。

4.1 写个 bug

ByteBuffer.allocate(capability) 是分拨 JVM 堆内存,属于 GC 统治限制,需要内存拷贝是以速率相对较慢; ByteBuffer.allocateDirect(capability) 是分拨 OS 土产货内存,不属于 GC 统治限制,由于不需要内存拷贝是以速率相对较快;

要是连接分拨土产货内存,堆内存很少使用,那么 JVM 就不需要践诺 GC,DirectByteBuffer 对象就不会被回收,这时天然堆内存充足,但土产货内存可能仍是不够用了,就会出现 OOM,土产货平直内存溢出。

/**  *  VM Options:-Xms10m,-Xmx10m,-XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m  */ public class DirectBufferMemoryDemo {      public static void main(String[] args) {         System.out.println("maxDirectMemory is:"+sun.misc.VM.maxDirectMemory() / 1024 / 1024 + "MB");          //ByteBuffer buffer = ByteBuffer.allocate(6*1024*1024);         ByteBuffer buffer = ByteBuffer.allocateDirect(6*1024*1024);      } } 

最大平直内存,默许是电脑内存的 1/4,是以咱们设小点,然后使用平直内存出奇这个值,就会出现 OOM。

maxDirectMemory is:5MB Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory 

4.2 处置决策

Java 只可通过 ByteBuffer.allocateDirect 顺序使用 Direct ByteBuffer,因此,不错通过 Arthas 等在线会诊器具阻止该顺序进行排查 查验是否平直或曲折使用了 NIO,如 netty,jetty 等 通过启动参数 -XX:MaxDirectMemorySize 盘曲 Direct ByteBuffer 的上限值 查验 JVM 参数是否有 -XX:+DisableExplicitGC 选项,要是有就去掉,因为该参数会使 System.gc() 失效 查验堆外内存使用代码,阐明是否存在内存流露;大要通过反射调用 sun.misc.Cleaner 的 clean() 顺序来主动开释被 Direct ByteBuffer 持有的内存空间 内存容量如实不及,升级成立

五、Unable to create new native thread

每个 Java 线程都需要占用一定的内存空间,当 JVM 向底层操作系统请求创建一个新的 native 线程时,要是莫得满盈的资源分拨就会报此类空虚。

5.1 写个 bug

public static void main(String[] args) {   while(true){     new Thread(() -> {       try {         Thread.sleep(Integer.MAX_VALUE);       } catch(InterruptedException e) { }     }).start();   } } Error occurred during initialization of VM java.lang.OutOfMemoryError: unable to create new native thread 

5.2 原因分析

JVM 向 OS 请求创建 native 线程失败,就会抛出 Unableto createnewnativethread,常见的原因包括以下几类: 线程数出奇操作系统最大线程数纵容(和平台联系) 线程数出奇 kernel.pid_max(只可重启) native 内存不及;该问题发生的常见过程主要包括以下几步: JVM 里面的应用要津请求创建一个新的 Java 线程; JVM native 顺序代理了该次请求,并向操作系统请求创建一个 native 线程; 操作系统尝试创建一个新的 native 线程,并为其分拨内存; 要是操作系统的造谣内存已耗尽,或是受到 32 位程度的地址空间纵容,操作系统就会拒却本次 native 内存分拨; JVM 将抛出 java.lang.OutOfMemoryError:Unableto createnewnativethread 空虚。

5.3 处置决策

想办法裁减要津中创建线程的数量,分析应用是否确实需要创建这样多线程

要是如实需要创建许多线程,调高 OS 层面的线程最大数:践诺 ulimia-a 查抄最大线程数纵容,使用 ulimit-u xxx 盘曲最大线程数纵容

六、Metaspace

JDK 1.8 之前会出现 Permgen space,该空虚暗示恒久代(Permanent Generation)已用满,平日是因为加载的 class 数量太多或体积太大。跟着 1.8 中恒久代的取消,就不会出现这种特地了。

Metaspace 是顺序区在 HotSpot 中的竣事,它与恒久代最大的辞别在于,元空间并不在造谣机内存中而是使用土产货内存,但是土产货内存也有打满的时候,是以也会有特地。

6.1 写个 bug

据介绍,“摇一摇”功能是指用户在打开一个软件时,开屏广告界面稍有摇晃就会自动进入广告详情页面、跳转打开广告相关软件甚至直接进入软件下载页面。

但是,效果如何呢?事实上,在iPhone 13发布之后,苹果在高端市场的地位是越来越稳固。众所周知,从mini到Pro Max,iPhone 13系列的覆盖价位是5199元到8999元。

/**  * JVM Options: -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m  */ public class MetaspaceOOMDemo {      public static void main(String[] args) {          while (true) {             Enhancer enhancer = new Enhancer();             enhancer.setSuperclass(MetaspaceOOMDemo.class);             enhancer.setUseCache(false);             enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {                 //动态代理创建对象                 return methodProxy.invokeSuper(o, objects);             });             enhancer.create();         }     } } 

借助 Spring 的 GCLib 竣事动态创建对象

Exception in thread "main" org.springframework.cglib.core.CodeGenerationException: java.lang.OutOfMemoryError-->Metaspace 

6.2 处置决策

顺序区溢出亦然一种常见的内存溢出特地,在往往运行时生成无边动态类的应用场景中,就应该相当温情这些类的回收情况。这类场景除了上边的 GCLib 字节码增强和动态言语外,常见的还有,无边 JSP 或动态产生 JSP 文献的应用(邃古时间的传统软件行业可能会有)、基于 OSGi 的应用(即使并吞个类文献,被不同的加载器加载也会视为不同的类)等。

顺序区在 JDK8 中一般不太容易产生,HotSpot 提供了一些参数来竖立元空间,不错起到防护作用

-XX:MaxMetaspaceSize 竖立元空间最大值,默许是 -1,暗示不纵容(如故要受土产货内存大小纵容的) -XX:MetaspaceSize 指定元空间的开动空间大小,以字节为单元,达到该值就会触发 GC 进行类型卸载,同期网罗器会对该值进行盘曲 -XX:MinMetaspaceFreeRatio 在 GC 之后戒指最小的元空间剩余容量的百分比,可减少因元空间不及导致的垃圾网罗频率,类似的还有 MaxMetaspaceFreeRatio

七、Requested array size exceeds VM limit

7.1 写个 bug

public static void main(String[] args) {   int[] arr = new int[Integer.MAX_VALUE]; } 

这个相比浅显,建个超等大数组就会出现 OOM,未几说了

Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit 

JVM 纵容了数组的最大长度,该空虚暗示要津请求创建的数组出奇最大长度纵容。

JVM 在为数组分拨内存前,会查验要分拨的数据结构在系统中是否可寻址,平日为 Integer.MAX_VALUE-2。

此类问题相比冷落,平日需要查验代码,阐明业务是否需要创建如斯大的数组,是否不错拆分为多个块,分批践诺。

八、Out of swap space

启动 Java 应用要津会分拨有限的内存。此纵容是通过-Xmx和其他类似的启动参数指定的。

在 JVM 请求的总内存大于可用物理内存的情况下,操作系统首先将内容从内存换出到硬盘驱动器。

该空虚暗示扫数可用的造谣内存已被耗尽。造谣内存(Virtual Memory)由物理内存(Physical Memory)和交换空间(Swap Space)两部分构成。

这种空虚没见过~~~

九、Kill process or sacrifice child

操作系统是建立在经由见解之上的。这些程度由几个内核功课谨慎,其中一个名为“ Out of memory Killer”,它会在可用内存极低的情况下“杀死”(kill)某些程度。OOM Killer 会对扫数程度进行打分,然后将评分较低的程度“杀死”,具体的评分公法不错参考 Surviving the Linux OOM Killer。

不同于其他的 OOM 空虚, Killprocessorsacrifice child 空虚不是由 JVM 层面触发的,而是由操作系统层面触发的。

9.1 原因分析

默许情况下,Linux 内核允许程度肯求的内存总量大于系统可用内存,通过这种“错峰复用”的面貌不错更有用的欺骗系统资源。

但是,这种面貌也会无可幸免地带来一定的“超卖”风险。举例某些程度持续占用系统内存,然后导致其他程度莫得可用内存。此时,系统将自动激活 OOM Killer,寻找评分低的程度,并将其“杀死”,开释内存资源。

9.2 处置决策

升级工作器成立/窒碍部署,幸免争用 OOM Killer 调优。

临了附上一张“涯海”大神的图

《长远清爽 Java 造谣机 第 3 版》

https://plumbr.io/outofmemoryerror

https://yq.aliyun.com/articles/711191

https://github.com/StabilityMan/StabilityGuide/blob/master/docs/diagnosis/jvm/exception

本文转载自微信公众号「JavaKeeper」,作家海星 。转载本文请谋划 JavaKeeper公众号。

 

原文连结:https://mp.weixin.qq.com/s/gIJvtd8rrZz6ttaoGLddLg

 



上一篇:人人视频综合网终末输在了这位一问三不知的手里
下一篇:人人视频综合网佛家强调生命有“成住坏空”的轮回
TOP