精华内容
下载资源
问答
  • Java面试】Java 内存溢出 栈溢出的原因与排查方法
    2022-03-24 15:38:25

    1、 内存溢出的原因是什么?

    内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,造成的内存溢出。如果出现这种现象可行代码排查:

    一)是否App中的类中和引用变量过多使用了Static修饰 如public staitc Student s;在类中的属性中使用 static修饰的最好只用基本类型或字符串。如public static int i = 0; //public static String str;
    二)是否App中使用了大量的递归或无限递归(递归中用到了大量的建新的对象)
    三)是否App中使用了大量循环或死循环(循环中用到了大量的新建的对象)
    四)检查App中是否使用了向数据库查询所有记录的方法。即一次性全部查询的方法,如果数据量超过10万多条了,就可能会造成内存溢出。所以在查询时应采用“分页查询”。
    五)检查是否有数组,List,Map中存放的是对象的引用而不是对象,因为这些引用会让对应的对象不能被释放。会大量存储在内存中。
    六)检查是否使用了“非字面量字符串进行+”的操作。因为String类的内容是不可变的,每次运行"+"就会产生新的对象,如果过多会造成新String对象过多,从而导致JVM没有及时回收而出现内存溢出。

    如String s1 = “My name”;
    String s2 = “is”;
    String s3 = “xuwei”;
    String str = s1 + s2 + s3 +…;这是会容易造成内存溢出的
    但是String str = “My name” + " is " + " xuwei" + " nice " + " to " + " meet you"; //但是这种就不会造成内存溢出。因为这是”字面量字符串“,在运行"+"时就会在编译期间运行好。不会按照JVM来执行的。

    在使用String,StringBuffer,StringBuilder时,如果是字面量字符串进行"+“时,应选用String性能更好;如果是String类进行”+"时,在不考虑线程安全时,应选用StringBuilder性能更好。

    七)使用 DDMS工具进行查找内存溢出的大概位置

    class Solution {
    	private String aString = "abc";
    
    	public void add() {
    		while (true) {
    			aString += aString;
    		}
    	}
    
    	public static void main(String[] args) {
    		new Solution().add();
    	}
    }
    

    2、栈溢出的原因

    一)、是否有递归调用
    二)、是否有大量循环或死循环
    三)、全局变量是否过多
    四)、 数组、List、map数据是否过大
    五)使用DDMS工具进行查找大概出现栈溢出的位置

    栈溢出的例子:

    class Solution {
    	int count = 0;
    	public void add() {
    		System.out.println(count++);
    		add();
    	}
    
    	public static void main(String[] args) {
    		new Solution().add();
    	}
    }
    
    更多相关内容
  • 重点问了Java线程锁:synchronized 和ReentrantLock相关的底层实现 线程池的底层实现以及常见的参数 数据结构基本都问了一遍:链表、队列等 Java内存模型:常问的JVM分代模型,以及JDK1.8后的区别,最后还问了JVM...

    01 阿里中间件(四面,Java岗)

    image

    1.1 Java中间件一面

    技术一面考察范围

    重点问了Java线程锁:synchronized 和ReentrantLock相关的底层实现 线程池的底层实现以及常见的参数 数据结构基本都问了一遍:链表、队列等 Java内存模型:常问的JVM分代模型,以及JDK1.8后的区别,最后还问了JVM相关的调优参数 分布式锁的实现比较技术

    一面题目

    • 自我介绍

    • 擅长哪方面的技术?

    • java有哪些锁中类?(乐观锁&悲观锁、可重入锁&Synchronize等)。

    • 比较重要的数据结构,如链表,队列,栈的基本原理及大致实现

    • J.U.C下的常见类的使用。Threadpool的深入考察;blockingQueue的使用

    • Java内存分代模型,GC算法,JVM常见的启动参数;CMS算法的过程。

    • Volatile关键字有什么用(包括底层原理)

    • 线程池的调优策略

    • Spring cloud的服务注册与发现是怎么设计的?

    • 分布式系统的全局id如何实现

    • 分布式锁的方案,redis和zookeeper那个好,如果是集群部署,高并发情况下那个性能更好。

    1.2 Java中间件二面

    技术二面考察范围:

    问了项目相关的技术实现细节 数据库相关:索引、索引底层实现、mysql相关的行锁、表锁等 redis相关:架构设计、数据一致性问题 容器:容器的设计原理等技术

    二面题目:

    • 参与的项目,选一个,技术难度在哪里?

    • Collections.sort底层排序方式

    • 负载均衡的原理设计模式与重构,谈谈你对重构的理解

    • 谈谈redis相关的集群有哪些成熟方案?

    • 再谈谈一致hash算法(redis)?

    • 数据库索引,B+树的特性和建树过程

    • Mysql相关的行锁,表锁;乐观锁,悲观锁

    • 谈谈多线程和并发工具的使用

    • 谈谈redis的架构和组件

    • Redis的数据一致性问题(分布式多节点环境&单机环境)

    • Docker容器

    1.3 Java中间件三面

    技术三面考察范围:

    主要谈到了高并发的实现方案 以及中间件:redis、rocketmq、kafka等的架构设计思路 最后问了平时怎么提升技术的技术

    三面题目

    • 高并发情况下,系统是如何支撑大量的请求的?

    • 接着上面的问题,延伸到了中间件,kafka、redis、rocketmq、mycat等设计思路和适用场景等

    • 最近上过哪些技术网站;最近再看那些书。

    • 工作和生活中遇见最大的挑战,怎么去克服?

    • 未来有怎样的打算

    1.4 Java中间件四面

    最后,你懂的,主要就是HR走流程了,主要问了未来的职业规划。

    02 头条Java后台3面

    image

    2.1 头条一面

    • 讲讲jvm运行时数据库区

    • 讲讲你知道的垃圾回收算法

    • jvm内存模型jmm

    • 内存泄漏与内存溢出的区别

    • select、epool 的区别?底层的数据结构是什么?

    • mysql数据库默认存储引擎,有什么优点

    • 优化数据库的方法,从sql到缓存到cpu到操作系统,知道多少说多少

    • 什么情景下做分表,什么情景下做分库

    • linkedList与arrayList区别 适用场景

    • array list是如何扩容的

    • volatile 关键字的作用?Java 内存模型?

    • java lock的实现,公平锁、非公平锁

    • 悲观锁和乐观锁,应用中的案例,mysql当中怎么实现,java中的实现

    2.2 头条二面

    • Java 内存分配策略?

    • 多个线程同时请求内存,如何分配?

    • Redis 底层用到了哪些数据结构?

    • 使用 Redis 的 set 来做过什么?

    • Redis 使用过程中遇到什么问题?

    • 搭建过 Redis 集群吗?

    • 如何分析“慢查询”日志进行 SQL/索引 优化?

    • MySQL 索引结构解释一下?(B+ 树)

    • MySQL Hash 索引适用情况?举下例子?

    2.3 头条三面

    • 如何保证数据库与redis缓存一致的Redis 的并发竞争问题是什么?

    • 如何解决这个问题?

    • 了解 Redis 事务的 CAS 方案吗?

    • 如何保证 Redis 高并发、高可用?

    • Redis 的主从复制原理,以及Redis 的哨兵原理?

    • 如果让你写一个消息队列,该如何进行架构设计啊?说一下你的思路。

    • MySQL数据库主从同步怎么实现?

    • 秒杀模块怎么设计的,如何压测,抗压手段

    03 今日头条Java后台研发三面

    image

    3.1 一面

    • concurrent包下面用过哪些?

    • countdownlatch功能实现

    • synchronized和lock区别,重入锁thread和runnable的区别

    • AtomicInteger实现原理(CAS自旋)

    • java并发sleep与wait、notify与notifyAll的区别

    • 如何实现高效的同步链表

    • java都有哪些加锁方式(synchronized、ReentrantLock、共享锁、读写锁等)

    • 设计模式(工厂模式、单例模式(几种情况)、适配器模式、装饰者模式)

    • maven依赖树,maven的依赖传递,循环依赖

    3.2 二面

    • synchronized和reentrantLock的区别,synchronized用在代码快、方法、静态方法时锁的都是什么?

    • 介绍spring的IOC和AOP,分别如何实现(classloader、动态代理)JVM的内存布局以及垃圾回收原理及过程

    • 讲一下,讲一下CMS垃圾收集器垃圾回收的流程,以及CMS的缺点

    • redis如何处理分布式服务器并发造成的不一致OSGi的机制spring中bean加载机制,bean生成的具体步骤,ioc注入的方式spring何时创建- applicationContextlistener是监听哪个事件?

    • 介绍ConcurrentHashMap原理,用的是哪种锁,segment有没可能增大?

    • 解释mysql索引、b树,为啥不用平衡二叉树、红黑树

    • Zookeeper如何同步配置

    3.3 三面

    • Java线程池ThreadPoolEcecutor参数,基本参数,使用场景

    • MySQL的ACID讲一下,延伸到隔离级别

    • dubbo的实现原理,说说RPC的要点

    • GC停顿原因,如何降低停顿?

    • JVM如何调优、参数怎么调?

    • 如何用工具分析jvm状态(visualVM看堆中对象的分配,对象间的引用、是否有内存泄漏,jstack看线程状态、是否死锁等等)

    • 描述一致性hash算法

    • 分布式雪崩场景如何避免?

    • 再谈谈消息队列

    04 抖音Java 三面

    image

    4.1 一面:

    • hashmap,怎么扩容,怎么处理数据冲突?

    • 怎么高效率的实现数据迁移?

    • Linux的共享内存如何实现,大概说了一下。

    • socket网络编程,说一下TCP的三次握手和四次挥手同步IO和异步IO的区别?

    • Java GC机制?GC Roots有哪些?

    • 红黑树讲一下,五个特性,插入删除操作,时间复杂度?

    • 快排的时间复杂度,最坏情况呢,最好情况呢,堆排序的时间复杂度呢,建堆的复杂度是多少

    4.2 二面:

    • 自我介绍,主要讲讲做了什么和擅长什么

    • 设计模式了解哪些?

    • AtomicInteger怎么实现原子修改的?

    • ConcurrentHashMap 在Java7和Java8中的区别?

    • 为什么Java8并发效率更好?什么情况下用HashMap,什么情况用ConcurrentHashMap?

    • redis数据结构?

    • redis数据淘汰机制?

    4.3 三面(约五十分钟):

    • mysql实现事务的原理(MVCC)

    • MySQL数据主从同步是如何实现的?

    • MySQL索引的实现,innodb的索引,b+树索引是怎么实现的,为什么用b+树做索引节点,一个节点存了多少数据,怎么规定大小,与磁盘页对应。

    • 如果Redis有1亿个key,使用keys命令是否会影响线上服务?

    • Redis的持久化方式,aod和rdb,具体怎么实现,追加日志和备份文件,底层实现原理的话知道么?

    • 遇到最大困难是什么?怎么克服?

    • 未来的规划是什么?

    • 你想问我什么?

    05 百度三面

    image

    5.1 百度一面

    • 自我介绍

    • Java中的多态

    • 为什么要同时重写hashcode和equals

    • Hashmap的原理

    • Hashmap如何变线程安全,每种方式的优缺点

    • 垃圾回收机制

    • Jvm的参数你知道的说一下

    • 设计模式了解的说一下啊

    • 手撕一个单例模式

    • 手撕算法:反转单链表

    • 手撕算法:实现类似微博子结构的数据结构,输入一系列父子关系,输出一个类似微博评论的父子结构图

    • 手写java多线程

    • 手写java的soeket编程,服务端和客户端

    • 手撕算法: 爬楼梯,写出状态转移方程

    • 智力题:时针分针什么时候重合

    5.2 百度二面(现场)

    • 自我介绍

    • 项目介绍

    • 服务器如何负载均衡,有哪些算法,哪个比较好,一致性哈希原理,怎么避免DDOS攻击请求打到少数机器。

    • TCP连接中的三次握手和四次挥手,四次挥手的最后一个ack的作用是什么,为什么要time wait,为什么是2msl。

    • 数据库的备份和恢复怎么实现的,主从复制怎么做的,什么时候会出现数据不一致,如何解决。

    • Linux查看cpu占用率高的进程

    • 手撕算法:给定一个数字三角形,找到从顶部到底部的最小路径和。每一步可以移动到下面一行的相邻数字上。

    • 然后继续在这个问题上扩展

    • 求出最短那条的路径

    • 递归求出所有的路径

    • 设计模式讲一下熟悉的

    • 会不会滥用设计模式

    • 多线程条件变量为什么要在while体里

    • 你遇到什么挫折,怎么应对和处理

    5.3 百度三面(现场)

    • 自我介绍

    • 项目介绍

    • Redis的特点

    • Redis的持久化怎么做,aof和rdb,有什么区别,有什么优缺点。

    • Redis使用哨兵部署会有什么问题,我说需要扩容的话还是得集群部署。

    • 说一下JVM内存模型把,有哪些区,分别干什么的

    • 说一下gc算法,分代回收说下

    • MySQL的引擎讲一下,有什么区别,使用场景呢

    • 分布式事务了解么

    • 反爬虫的机制,有哪些方式

    06 蚂蚁中间件团队面试题

    image

    6.1 蚂蚁中间件一面:

    • 自我介绍

    • JVM垃圾回收算法和垃圾回收器有哪些,最新的JDK采用什么算法。

    • 新生代和老年代的回收机制。

    • 讲一下ArrayList和linkedlist的区别,ArrayList与HashMap的扩容方式。

    • Concurrenthashmap1.8后的改动。

    • Java中的多线程,以及线程池的增长策略和拒绝策略了解么。

    • Tomcat的类加载器了解么

    • Spring的ioc和aop,Springmvc的基本架构,请求流程。

    • HTTP协议与Tcp有什么区别,http1.0和2.0的区别。

    • Java的网络编程,讲讲NIO的实现方式,与BIO的区别,以及介绍常用的NIO框架。

    • 索引什么时候会失效变成全表扫描

    • 介绍下分布式的paxos和raft算法

    6.2 蚂蚁中间件二面

    • 你在项目中怎么用到并发的。

    • 消息队列的使用场景,谈谈Kafka。

    • 你说了解分布式服务,那么你怎么理解分布式服务。

    • Dubbo和Spring Clound的区别,以及使用场景。

    • 讲一下docker的实现原理,以及与JVM的区别。

    • MongoDB、Redis和Memcached的应用场景,各自优势

    • MongoDB有事务吗

    • Redis说一下sorted set底层原理

    • 讲讲Netty为什么并发高,相关的核心组件有哪些

    6.3 蚂蚁中间件三面

    • 完整的画一个分布式集群部署图,从负载均衡到后端数据库集群。

    • 分布式锁的方案,Redis和Zookeeper哪个好,如果是集群部署,高并发情况下哪个性能更好。

    • 分布式系统的全局id如何实现。

    • 数据库万级变成亿级,你如何来解决。

    • 常见的服务器雪崩是由什么引起的,如何来防范。

    • 异地容灾怎么实现

    • 常用的高并发技术解决方案有哪些,以及对应的解决步骤。

    07 京东4面(Java研发)

    image

    7.1 一面(基础面:约1小时)

    • 自我介绍,主要讲讲做了什么和擅长什么

    • springmvc和spring-boot区别

    • @Autowired的实现原理

    • Bean的默认作用范围是什么?其他的作用范围?

    • 索引是什么概念有什么作用?MySQL里主要有哪些索引结构?哈希索引和B+树索引比较?

    • Java线程池的原理?线程池有哪些?线程池工厂有哪些线程池类型,及其线程池参数是什么?

    • hashmap原理,处理哈希冲突用的哪种方法?

    • 还知道什么处理哈希冲突的方法?

    • Java GC机制?GC Roots有哪些?

    • Java怎么进行垃圾回收的?什么对象会进老年代?垃圾回收算法有哪些?为什么新生代使用复制算法?

    • HashMap的时间复杂度?HashMap中Hash冲突是怎么解决的?链表的上一级结构是什么?Java8中的HashMap有什么变化?红黑树需要比较大小才能进行插入,是依据什么进行比较的?其他Hash冲突解决方式?

    • hash和B+树的区别?分别应用于什么场景?哪个比较好?

    • 项目里有个数据安全的,aes和md5的区别?详细点

    7.2 二面(问数据库较多)

    • 自我介绍

    • 为什么MyISAM查询性能好?

    • 事务特性(acid)

    • 隔离级别

    • SQL慢查询的常见优化步骤?

    • 说下乐观锁,悲观锁(select for update),并写出sql实现

    • TCP协议的三次握手和四次挥手过程?

    • 用到过哪些rpc框架

    • 数据库连接池怎么实现

    • Java web过滤器的生命周期

    7.3 三面(综合面;约一个小时)

    • 自我介绍。

    • ConcurrentHashMap 在Java7和Java8中的区别?为什么Java8并发效率更好?什么情况下用HashMap,什么情况用ConcurrentHashMap?

    • 加锁有什么机制?

    • ThreadLocal?应用场景?

    • 数据库水平切分,垂直切分的设计思路和切分顺序

    • Redis如何解决key冲突

    • soa和微服务的区别?

    • 单机系统演变为分布式系统,会涉及到哪些技术的调整?请从前面负载到后端详细描述。

    • 设计一个秒杀系统?

    7.4 四面(HR面)

    • 你自己最大优势和劣势是什么

    • 平时遇见过什么样的挑战,怎么去克服的

    • 工作中遇见了技术解决不了的问题,你的应对思路?

    • 你的兴趣爱好?

    • 未来的职业规划是什么?

    08 美团java高级开发3面

    image

    8.1 美团一面

    • 自我介绍

    • 项目介绍

    • Redis介绍

    • 了解redis源码么

    • 了解redis集群么

    • Hashmap的原理,增删的情况后端数据结构如何位移

    • hashmap容量为什么是2的幂次

    • hashset的源码

    • object类你知道的方法

    • hashcode和equals

    • 你重写过hashcode和equals么,要注意什么

    • 假设现在一个学生类,有学号和姓名,我现在hashcode方法重写的时候,只将学号参与计算,会出现什么情况?

    • 往set里面put一个学生对象,然后将这个学生对象的学号改了,再put进去,可以放进set么?并讲出为什么

    • Redis的持久化?有哪些方式,原理是什么?

    • 讲一下稳定的排序算法和不稳定的排序算法

    • 讲一下快速排序的思想

    8.2 美团二面

    • 自我介绍

    • 讲一下数据的acid

    • 什么是一致性

    • 什么是隔离性

    • Mysql的隔离级别

    • 每个隔离级别是如何解决

    • Mysql要加上nextkey锁,语句该怎么写

    • Java的内存模型,垃圾回收

    • 线程池的参数

    • 每个参数解释一遍

    • 然后面试官设置了每个参数,给了是个线程,让描述出完整的线程池执行的流程

    • Nio和IO有什么区别

    • Nio和aio的区别

    • Spring的aop怎么实现

    • Spring的aop有哪些实现方式

    • 动态代理的实现方式和区别

    • Linux了解么

    • 怎么查看系统负载

    • Cpu load的参数如果为4,描述一下现在系统处于什么情况

    • Linux,查找磁盘上最大的文件的命令

    • Linux,如何查看系统日志文件

    • 手撕算法:leeetcode原题 22,Generate Parentheses,给定 n 对括号,请- 写一个函数以将其生成新的括号组合,并返回所有组合结果。

    8.3 美团三面(现场)

    三面没怎么问技术,问了很多技术管理方面的问题

    • 自我介绍

    • 项目介绍

    • 怎么管理项目成员

    • 当意见不一致时,如何沟通并说服开发成员,并举个例子

    • 怎么保证项目的进度

    • 数据库的索引原理

    • 非聚簇索引和聚簇索引

    • 索引的使用注意事项

    • 联合索引

    • 从底层解释最左匹配原则

    • Mysql对联合索引有优化么?会自动调整顺序么?哪个版本开始优化?

    • Redis的应用

    • Redis的持久化的方式和原理

    • 技术选型,一个新技术和一个稳定的旧技术,你会怎么选择,选择的考虑有哪些

    • 说你印象最深的美团点评技术团队的三篇博客

    • 最近在学什么新技术

    • 你是怎么去接触一门新技术的

    • 会看哪些书

    • 怎么选择要看的书

    总结

    在这里,由于面试中MySQL问的比较多,因此也就在此以MySQL为例为大家总结分享。但是你要学习的往往不止这一点,还有一些主流框架的使用,Spring源码的学习,Mybatis源码的学习等等都是需要掌握的,我也把这些知识点都整理起来了,有需要的朋友可以**【转发+关注】后点击这里免费领取!**

    面试真题

    • 自我介绍

    • 项目介绍

    • 怎么管理项目成员

    • 当意见不一致时,如何沟通并说服开发成员,并举个例子

    • 怎么保证项目的进度

    • 数据库的索引原理

    • 非聚簇索引和聚簇索引

    • 索引的使用注意事项

    • 联合索引

    • 从底层解释最左匹配原则

    • Mysql对联合索引有优化么?会自动调整顺序么?哪个版本开始优化?

    • Redis的应用

    • Redis的持久化的方式和原理

    • 技术选型,一个新技术和一个稳定的旧技术,你会怎么选择,选择的考虑有哪些

    • 说你印象最深的美团点评技术团队的三篇博客

    • 最近在学什么新技术

    • 你是怎么去接触一门新技术的

    • 会看哪些书

    • 怎么选择要看的书

    总结

    在这里,由于面试中MySQL问的比较多,因此也就在此以MySQL为例为大家总结分享。但是你要学习的往往不止这一点,还有一些主流框架的使用,Spring源码的学习,Mybatis源码的学习等等都是需要掌握的,我也把这些知识点都整理起来了,有需要的朋友可以**【转发+关注】后点击这里免费领取!**

    [外链图片转存中…(img-ZjU0Xe1u-1627358677054)]

    Spring源码笔记

    展开全文
  • java内存溢出 原因与排查方法 1、 内存溢出的原因是什么? 内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,导致剩余的内存不够用,造成的内存溢出。如果出现这种现象可行代码排查: 一)是否应用...

    java内存溢出 原因与排查方法

    1、 内存溢出的原因是什么?

    内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,导致剩余的内存不够用,造成的内存溢出。如果出现这种现象可行代码排查:

    一)是否应用中的类中和引用变量过多使用了Static修饰 如public staitc Student s;在类中的属性中使用 static修饰的最好只用基本类型或字符串。如public static int i = 0; //public static String str;

    二)是否 应用 中使用了大量的递归或无限递归(递归中用到了大量的建新的对象)

    三)是否App中使用了大量循环或死循环(循环中用到了大量的新建的对象)

    四)检查 应用 中是否使用了向数据库查询所有记录的方法。即一次性全部查询的方法,如果数据量超过10万多条了,就可能会造成内存溢出。所以在查询时应采用“分页查询”。

    五)检查是否有数组,List,Map中存放的是对象的引用而不是对象,因为这些引用会让对应的对象不能被释放。会大量存储在内存中。

    六)检查是否使用了“非字面量字符串进行+”的操作。因为String类的内容是不可变的,每次运行"+"就会产生新的对象,如果过多会造成新String对象过多,从而导致JVM没有及时回收而出现内存溢出。

    如String s1 = "My name";

    String s2 = "is";

    String s3 = "xuwei";

    String str = s1 + s2 + s3 +.........;这是会容易造成内存溢出的

    但是String str =  "My name" + " is " + " xuwei" + " nice " + " to " + " meet you"; //但是这种就不会造成内存溢出。因为这是”字面量字符串“,在运行"+"时就会在编译期间运行好。不会按照JVM来执行的。

    在使用String,StringBuffer,StringBuilder时,如果是字面量字符串进行"+"时,应选用String性能更好;如果是String类进行"+"时,在不考虑线程安全时,应选用StringBuilder性能更好。

    public class Test {  
      
        public void testHeap(){  
            for(;;){  //死循环一直创建对象,堆溢出
                  ArrayList list = new ArrayList (2000);  
              }  
        }  
        int num=1;  
        public void testStack(){  //无出口的递归调用,栈溢出
            num++;  
            this.testStack();  
         }  
          
        public static void main(String[] args){  
            Test  t  = new Test ();  
            t.testHeap();  
            t.testStack();     
        }  
    } 

     

    2、栈溢出的原因

     一)、是否有递归调用

    二)、是否有大量循环或死循环

    三)、全局变量是否过多

    四)、 数组、List、map数据是否过大

    五)使用DDMS工具进行查找大概出现栈溢出的位置

    后续持续更新 请看到的及时补充到评论区……

    下面是摘自掘金中的一篇文章,在项目过程中或多或少遇到过,由于本人不想再一一做测试用例,就摘录过来了,最后附带地址链接 ,可以方便大家去看原文(尊重原著)

     

    JVM系列之实战内存溢出异常

    实战内存溢出异常

    大家好,相信大部分Javaer在code时经常会遇到本地代码运行正常,但在生产环境偶尔会莫名其妙的报一些关于内存的异常,StackOverFlowError,OutOfMemoryError异常是最常见的。今天就基于上篇文章JVM系列之Java内存结构详解讲解的各个内存区域重点实战分析下内存溢出的情况。在此之前,我还是想多余累赘一些其他关于对象的问题,具体内容如下:

    文章结构

    对象的创建过程
    对象的内存布局
    对象的访问定位
    实战内存异常

    1 . 对象的创建过程

    关于对象的创建,第一反应是new关键字,那么本文就主要讲解new关键字创建对象的过程。

    Student stu =new Student("张三","18");

    就拿上面这句代码来说,虚拟机首先会去检查Student这个类有没有被加载,如果没有,首先去加载这个类到方法区,然后根据加载的Class类对象创建stu实例对象,需要注意的是,stu对象所需的内存大小在Student类加载完成后便可完全确定。内存分配完成后,虚拟机需要将分配到的内存空间的实例数据部分初始化为零值,这也就是为什么我们在编写Java代码时创建一个变量不需要初始化。紧接着,虚拟机会对对象的对象头进行必要的设置,如这个对象属于哪个类,如何找到类的元数据(Class对象),对象的锁信息,GC分代年龄等。设置完对象头信息后,调用类的构造函数。
    其实讲实话,虚拟机创建对象的过程远不止这么简单,我这里只是把大致的脉络讲解了一下,方便大家理解。

    2 . 对象的内存布局

    刚刚提到的实例数据,对象头,有些小伙伴也许有点陌生,这一小节就详细讲解一下对象的内存布局,对象创建完成后大致可以分为以下几个部分:

    对象头
    实例数据
    对齐填充

    对象头: 对象头中包含了对象运行时一些必要的信息,如GC分代信息,锁信息,哈希码,指向Class类元信息的指针等,其中对Javaer比较有用的是锁信息与指向Class对象的指针,关于锁信息,后期有机会讲解并发编程JUC时再扩展,关于指向Class对象的指针其实很好理解。比如上面那个Student的例子,当我们拿到stu对象时,调用Class stuClass=stu.getClass();的时候,其实就是根据这个指针去拿到了stu对象所属的Student类在方法区存放的Class类对象。虽然说的有点拗口,但这句话我反复琢磨了好几遍,应该是说清楚了。

    实例数据:实例数据部分是对象真正存储的有效信息,就是程序代码中所定义的各种类型的字段内容。

    对齐填充:虚拟机规范要求对象大小必须是8字节的整数倍。对齐填充其实就是来补全对象大小的。

    3 . 对象的访问定位

    谈到对象的访问,还拿上面学生的例子来说,当我们拿到stu对象时,直接调用stu.getName();时,其实就完成了对对象的访问。但这里要累赘说一下的是,stu虽然通常被认为是一个对象,其实准确来说是不准确的,stu只是一个变量,变量里存储的是指向对象的指针,(如果干过C或者C++的小伙伴应该比较清楚指针这个概念),当我们调用stu.getName()时,虚拟机会根据指针找到堆里面的对象然后拿到实例数据name.需要注意的是,当我们调用stu.getClass()时,虚拟机会首先根据stu指针定位到堆里面的对象,然后根据对象头里面存储的指向Class类元信息的指针再次到方法区拿到Class对象,进行了两次指针寻找。具体讲解图如下:

     

    4 .实战内存异常

    内存异常是我们工作当中经常会遇到问题,但如果仅仅会通过加大内存参数来解决问题显然是不够的,应该通过一定的手段定位问题,到底是因为参数问题,还是程序问题(无限创建,内存泄露)。定位问题后才能采取合适的解决方案,而不是一内存溢出就查找相关参数加大。

    概念:
    内存泄露:代码中的某个对象本应该被虚拟机回收,但因为拥有GCRoot引用而没有被回收。关于GCRoot概念,下一篇文章讲解。
    内存溢出: 虚拟机由于堆中拥有太多不可回收对象没有回收,导致无法继续创建新对象。

    在分析问题之前先给大家讲一讲排查内存溢出问题的方法,内存溢出时JVM虚拟机会退出,那么我们怎么知道JVM运行时的各种信息呢,Dump机制会帮助我们,可以通过加上VM参数-XX:+HeapDumpOnOutOfMemoryError让虚拟机在出现内存溢出异常时生成dump文件,然后通过外部工具(作者使用的是VisualVM)来具体分析异常的原因。

    下面从以下几个方面来配合代码实战演示内存溢出及如何定位:

    Java堆内存异常
    Java栈内存异常
    方法区内存异常

    Java堆内存异常

    /** VM Args: //这两个参数保证了堆中的可分配内存固定为20M -Xms20m -Xmx20m 
    //文件生成的位置,则生成在桌面的一个目录 -XX:+HeapDumpOnOutOfMemoryError 
    //文件生成的位置,则生成在桌面的一个目录 
    //文件生成的位置,则生成在桌面的一个目录 -XX:HeapDumpPath=/Users/zdy/Desktop/dump/ */
    public class HeapOOM {
        //创建一个内部类用于创建对象使用
        static class OOMObject {
        }
        public static void main(String[] args) {
            List<OOMObject> list = new ArrayList<OOMObject>();
            //无限创建对象,在堆中
            while (true) {
                list.add(new OOMObject());
            }
        }
    }

    Run起来代码后爆出异常如下:

    java.lang.OutOfMemoryError: Java heap space
    Dumping heap to /Users/zdy/Desktop/dump/java_pid1099.hprof ...

    可以看到生成了dump文件到指定目录。并且爆出了OutOfMemoryError,还告诉了你是哪一片区域出的问题:heap space

    打开VisualVM工具导入对应的heapDump文件(如何使用请读者自行查阅相关资料),相应的说明见图:

    分析dump文件后,我们可以知道,OOMObject这个类创建了810326个实例。所以它能不溢出吗?接下来就在代码里找这个类在哪new的。排查问题。(我们的样例代码就不用排查了,While循环太凶猛了)

    Java栈内存异常

    老实说,在栈中出现异常(StackOverFlowError)的概率很小,小到和去苹果专卖店买手机,买回来后发现是Android系统的概率是一样的。因为作者确实没有在生产环境中遇到过,除了自己作死写样例代码测试。先说一下异常出现的情况,前面讲到过,方法调用的过程就是方法帧进虚拟机栈和出虚拟机栈的过程,那么有两种情况可以导致StackOverFlowError,当一个方法帧(比如需要2M内存)进入到虚拟机栈(比如还剩下1M内存)的时候,就会报出StackOverFlow.这里先说一个概念,栈深度:指目前虚拟机栈中没有出栈的方法帧。虚拟机栈容量通过参数-Xss来控制,下面通过一段代码,把栈容量人为的调小一点,然后通过递归调用触发异常。

    /** * VM Args: //设置栈容量为160K,默认1M -Xss160k */
    public class JavaVMStackSOF {
        private int stackLength = 1;
        public void stackLeak() {
            stackLength++;
            //递归调用,触发异常
            stackLeak();
        }
    
        public static void main(String[] args) throws Throwable {
            JavaVMStackSOF oom = new JavaVMStackSOF();
            try {
                oom.stackLeak();
            } catch (Throwable e) {
                System.out.println("stack length:" + oom.stackLength);
                throw e;
            }
        }
    }

    结果如下:
    stack length:751
    Exception in thread "main" java.lang.StackOverflowError

    可以看到,递归调用了751次,栈容量不够用了。
    默认的栈容量在正常的方法调用时,栈深度可以达到1000-2000深度,所以,一般的递归是可以承受的住的。如果你的代码出现了StackOverflowError,首先检查代码,而不是改参数。

    这里顺带提一下,很多人在做多线程开发时,当创建很多线程时,容易出现OOM(OutOfMemoryError),

    这时可以通过具体情况,减少最大堆容量,或者栈容量来解决问题,这是为什么呢。请看下面的公式:

    线程数 * (最大栈容量) + 最大堆值 + 其他内存(忽略不计或者一般不改动) = 机器最大内存

    当线程数比较多时,且无法通过业务上削减线程数,那么再不换机器的情况下,你只能把最大栈容量设置小一点,或者把最大堆值设置小一点

    方法区内存异常

    写到这里时,作者本来想写一个无限创建动态代理对象的例子来演示方法区溢出,避开谈论JDK7与JDK8的内存区域变更的过渡,但细想一想,还是把这一块从始致终的说清楚。在上一篇文章中JVM系列之Java内存结构详解讲到方法区时提到,JDK7环境下方法区包括了(运行时常量池),其实这么说是不准确的。因为从JDK7开始,HotSpot团队就想到开始去"永久代",大家首先明确一个概念,方法区和"永久代"(PermGen space)是两个概念,方法区是JVM虚拟机规范,任何虚拟机实现(J9等)都不能少这个区间,而"永久代"只是HotSpot对方法区的一个实现。为了把知识点列清楚,我还是才用列表的形式:

    JDK7之前(包括JDK7)拥有"永久代"(PermGen space),用来实现方法区。但在JDK7中已经逐渐在实现中把永久代中把很多东西移了出来,比如:符号引用(Symbols)转移到了native heap,运行时常量池(interned strings)转移到了java heap;类的静态变量(class statics)转移到了java heap。
    所以这就是为什么我说上一篇文章中说方法区中包含运行时常量池是不正确的,因为已经移动到了java heap;
    在JDK7之前(包括7)可以通过-XX:PermSize -XX:MaxPermSize来控制永久代的大小。
    JDK8正式去除"永久代",换成Metaspace(元空间)作为JVM虚拟机规范中方法区的实现。
    元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但仍可以通过参数控制:-XX:MetaspaceSize与-XX:MaxMetaspaceSize来控制大小。
    下面作者还是通过一段代码,来不停的创建Class对象,在JDK8中可以看到metaSpace内存溢出

    /** 作者准备在JDK8下测试方法区,所以设置了Metaspace的大小为固定的8M -XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=8m */
    
    public class JavaMethodAreaOOM {
    
        public static void main(String[] args) {
            while (true) {
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(OOMObject.class);
                enhancer.setUseCache(false);
                enhancer.setCallback(new MethodInterceptor() {
                    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                        return proxy.invokeSuper(obj, args);
                    }
                });
                //无限创建动态代理,生成Class对象
                enhancer.create();
            }
        }
    
        static class OOMObject {
    
        }
    }

    在JDK8的环境下将报出异常:
    Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
    这是因为在调用CGLib的创建代理时会生成动态代理类,即Class对象到Metaspace,所以While一下就出异常了。
    提醒一下:虽然我们日常叫"堆Dump",但是dump技术不仅仅是对于"堆"区域才有效,而是针对OOM的,也就是说不管什么区域,凡是能够报出OOM错误的,都可以使用dump技术生成dump文件来分析。

    在经常动态生成大量Class的应用中,需要特别注意类的回收状况,这类场景除了例子中的CGLib技术,常见的还有,大量JSP,反射,OSGI等。需要特别注意,当出现此类异常,应该知道是哪里出了问题,然后看是调整参数,还是在代码层面优化。

    附加-直接内存异常

    直接内存异常非常少见,而且机制很特殊,因为直接内存不是直接向操作系统分配内存,而且通过计算得到的内存不够而手动抛出异常,所以当你发现你的dump文件很小,而且没有明显异常,只是告诉你OOM,你就可以考虑下你代码里面是不是直接或者间接使用了NIO而导致直接内存溢出。

     

     

    原文地址https://my.oschina.net/u/2401092/blog/1621850

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    展开全文
  • 1、 内存溢出的原因是什么?内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,造成的内存溢出。如果出现这种现象可行代码排查:一)是否应用中的类中和引用变量过多使用了Static修饰 如public staitc ...

    1、 内存溢出的原因是什么?

    内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,造成的内存溢出。如果出现这种现象可行代码排查:

    一)是否应用中的类中和引用变量过多使用了Static修饰 如public staitc Student s;在类中的属性中使用 static修饰的最好只用基本类型或字符串。如public static int i = 0; //public static String str;

    二)是否 应用 中使用了大量的递归或无限递归(递归中用到了大量的建新的对象)

    三)是否App中使用了大量循环或死循环(循环中用到了大量的新建的对象)

    四)检查 应用 中是否使用了向数据库查询所有记录的方法。即一次性全部查询的方法,如果数据量超过10万多条了,就可能会造成内存溢出。所以在查询时应采用“分页查询”。

    五)检查是否有数组,List,Map中存放的是对象的引用而不是对象,因为这些引用会让对应的对象不能被释放。会大量存储在内存中。

    六)检查是否使用了“非字面量字符串进行+”的操作。因为String类的内容是不可变的,每次运行"+"就会产生新的对象,如果过多会造成新String对象过多,从而导致JVM没有及时回收而出现内存溢出。

    如String s1 = "My name";

    String s2 = "is";

    String s3 = "xuwei";

    String str = s1 + s2 + s3 +.........;这是会容易造成内存溢出的

    但是String str =  "My name" + " is " + " xuwei" + " nice " + " to " + " meet you"; //但是这种就不会造成内存溢出。因为这是”字面量字符串“,在运行"+"时就会在编译期间运行好。不会按照JVM来执行的。

    在使用String,StringBuffer,StringBuilder时,如果是字面量字符串进行"+"时,应选用String性能更好;如果是String类进行"+"时,在不考虑线程安全时,应选用StringBuilder性能更好。

    public class Test {

    public void testHeap(){

    for(;;){  //死循环一直创建对象,堆溢出

    ArrayList list = new ArrayList (2000);

    }

    }

    int num=1;

    public void testStack(){  //无出口的递归调用,栈溢出

    num++;

    this.testStack();

    }

    public static void main(String[] args){

    Test  t  = new Test ();

    t.testHeap();

    t.testStack();

    }

    }

    2、栈溢出的原因

    一)、是否有递归调用

    二)、是否有大量循环或死循环

    三)、全局变量是否过多

    四)、 数组、List、map数据是否过大

    五)使用DDMS工具进行查找大概出现栈溢出的位置

    后续持续更新 请看到的及时补充到评论区……

    下面是摘自掘金中的一篇文章,在项目过程中或多或少遇到过,由于本人不想再一一做测试用例,就摘录过来了,最后附带地址链接 ,可以方便大家去看原文(尊重原著)

    JVM系列之实战内存溢出异常

    实战内存溢出异常

    大家好,相信大部分Javaer在code时经常会遇到本地代码运行正常,但在生产环境偶尔会莫名其妙的报一些关于内存的异常,StackOverFlowError,OutOfMemoryError异常是最常见的。今天就基于上篇文章JVM系列之Java内存结构详解讲解的各个内存区域重点实战分析下内存溢出的情况。在此之前,我还是想多余累赘一些其他关于对象的问题,具体内容如下:

    文章结构

    对象的创建过程

    对象的内存布局

    对象的访问定位

    实战内存异常

    1 . 对象的创建过程

    关于对象的创建,第一反应是new关键字,那么本文就主要讲解new关键字创建对象的过程。

    Student stu =new Student("张三","18");

    就拿上面这句代码来说,虚拟机首先会去检查Student这个类有没有被加载,如果没有,首先去加载这个类到方法区,然后根据加载的Class类对象创建stu实例对象,需要注意的是,stu对象所需的内存大小在Student类加载完成后便可完全确定。内存分配完成后,虚拟机需要将分配到的内存空间的实例数据部分初始化为零值,这也就是为什么我们在编写Java代码时创建一个变量不需要初始化。紧接着,虚拟机会对对象的对象头进行必要的设置,如这个对象属于哪个类,如何找到类的元数据(Class对象),对象的锁信息,GC分代年龄等。设置完对象头信息后,调用类的构造函数。

    其实讲实话,虚拟机创建对象的过程远不止这么简单,我这里只是把大致的脉络讲解了一下,方便大家理解。

    2 . 对象的内存布局

    刚刚提到的实例数据,对象头,有些小伙伴也许有点陌生,这一小节就详细讲解一下对象的内存布局,对象创建完成后大致可以分为以下几个部分:

    对象头

    实例数据

    对齐填充

    对象头: 对象头中包含了对象运行时一些必要的信息,如GC分代信息,锁信息,哈希码,指向Class类元信息的指针等,其中对Javaer比较有用的是锁信息与指向Class对象的指针,关于锁信息,后期有机会讲解并发编程JUC时再扩展,关于指向Class对象的指针其实很好理解。比如上面那个Student的例子,当我们拿到stu对象时,调用Class stuClass=stu.getClass();的时候,其实就是根据这个指针去拿到了stu对象所属的Student类在方法区存放的Class类对象。虽然说的有点拗口,但这句话我反复琢磨了好几遍,应该是说清楚了。^_^

    实例数据:实例数据部分是对象真正存储的有效信息,就是程序代码中所定义的各种类型的字段内容。

    对齐填充:虚拟机规范要求对象大小必须是8字节的整数倍。对齐填充其实就是来补全对象大小的。

    3 . 对象的访问定位

    谈到对象的访问,还拿上面学生的例子来说,当我们拿到stu对象时,直接调用stu.getName();时,其实就完成了对对象的访问。但这里要累赘说一下的是,stu虽然通常被认为是一个对象,其实准确来说是不准确的,stu只是一个变量,变量里存储的是指向对象的指针,(如果干过C或者C++的小伙伴应该比较清楚指针这个概念),当我们调用stu.getName()时,虚拟机会根据指针找到堆里面的对象然后拿到实例数据name.需要注意的是,当我们调用stu.getClass()时,虚拟机会首先根据stu指针定位到堆里面的对象,然后根据对象头里面存储的指向Class类元信息的指针再次到方法区拿到Class对象,进行了两次指针寻找。具体讲解图如下:

    4 .实战内存异常

    内存异常是我们工作当中经常会遇到问题,但如果仅仅会通过加大内存参数来解决问题显然是不够的,应该通过一定的手段定位问题,到底是因为参数问题,还是程序问题(无限创建,内存泄露)。定位问题后才能采取合适的解决方案,而不是一内存溢出就查找相关参数加大。

    概念

    内存泄露:代码中的某个对象本应该被虚拟机回收,但因为拥有GCRoot引用而没有被回收。关于GCRoot概念,下一篇文章讲解。

    内存溢出: 虚拟机由于堆中拥有太多不可回收对象没有回收,导致无法继续创建新对象。

    在分析问题之前先给大家讲一讲排查内存溢出问题的方法,内存溢出时JVM虚拟机会退出,那么我们怎么知道JVM运行时的各种信息呢,Dump机制会帮助我们,可以通过加上VM参数-XX:+HeapDumpOnOutOfMemoryError让虚拟机在出现内存溢出异常时生成dump文件,然后通过外部工具(作者使用的是VisualVM)来具体分析异常的原因。

    下面从以下几个方面来配合代码实战演示内存溢出及如何定位:

    Java堆内存异常

    Java栈内存异常

    方法区内存异常

    Java堆内存异常

    /** VM Args: //这两个参数保证了堆中的可分配内存固定为20M -Xms20m -Xmx20m //文件生成的位置,作则生成在桌面的一个目录 -XX:+HeapDumpOnOutOfMemoryError //文件生成的位置,作则生成在桌面的一个目录 //文件生成的位置,作则生成在桌面的一个目录 -XX:HeapDumpPath=/Users/zdy/Desktop/dump/ */

    public class HeapOOM {

    //创建一个内部类用于创建对象使用

    static class OOMObject {

    }

    public static void main(String[] args) {

    List list = new ArrayList();

    //无限创建对象,在堆中

    while (true) {

    list.add(new OOMObject());

    }

    }

    }

    Run起来代码后爆出异常如下:

    java.lang.OutOfMemoryError: Java heap space

    Dumping heap to /Users/zdy/Desktop/dump/java_pid1099.hprof ...

    可以看到生成了dump文件到指定目录。并且爆出了OutOfMemoryError,还告诉了你是哪一片区域出的问题:heap space

    打开VisualVM工具导入对应的heapDump文件(如何使用请读者自行查阅相关资料),相应的说明见图:

    "类标签"

    切换到"实例数"标签页

    "实例数标签"

    分析dump文件后,我们可以知道,OOMObject这个类创建了810326个实例。所以它能不溢出吗?接下来就在代码里找这个类在哪new的。排查问题。(我们的样例代码就不用排查了,While循环太凶猛了)

    Java栈内存异常

    老实说,在栈中出现异常(StackOverFlowError)的概率小到和去苹果专卖店买手机,买回来后发现是Android系统的概率是一样的。因为作者确实没有在生产环境中遇到过,除了自己作死写样例代码测试。先说一下异常出现的情况,前面讲到过,方法调用的过程就是方法帧进虚拟机栈和出虚拟机栈的过程,那么有两种情况可以导致StackOverFlowError,当一个方法帧(比如需要2M内存)进入到虚拟机栈(比如还剩下1M内存)的时候,就会报出StackOverFlow.这里先说一个概念,栈深度:指目前虚拟机栈中没有出栈的方法帧。虚拟机栈容量通过参数-Xss来控制,下面通过一段代码,把栈容量人为的调小一点,然后通过递归调用触发异常。

    /** * VM Args: //设置栈容量为160K,默认1M -Xss160k */

    public class JavaVMStackSOF {

    private int stackLength = 1;

    public void stackLeak() {

    stackLength++;

    //递归调用,触发异常

    stackLeak();

    }

    public static void main(String[] args) throws Throwable {

    JavaVMStackSOF oom = new JavaVMStackSOF();

    try {

    oom.stackLeak();

    } catch (Throwable e) {

    System.out.println("stack length:" + oom.stackLength);

    throw e;

    }

    }

    }

    结果如下:

    stack length:751

    Exception in thread "main" java.lang.StackOverflowError

    可以看到,递归调用了751次,栈容量不够用了。

    默认的栈容量在正常的方法调用时,栈深度可以达到1000-2000深度,所以,一般的递归是可以承受的住的。如果你的代码出现了StackOverflowError,首先检查代码,而不是改参数。

    这里顺带提一下,很多人在做多线程开发时,当创建很多线程时,容易出现OOM(OutOfMemoryError),这时可以通过具体情况,减少最大堆容量,或者栈容量来解决问题,这是为什么呢。请看下面的公式:

    线程数*(最大栈容量)+最大堆值+其他内存(忽略不计或者一般不改动)=机器最大内存

    当线程数比较多时,且无法通过业务上削减线程数,那么再不换机器的情况下,你只能把最大栈容量设置小一点,或者把最大堆值设置小一点。

    方法区内存异常

    写到这里时,作者本来想写一个无限创建动态代理对象的例子来演示方法区溢出,避开谈论JDK7与JDK8的内存区域变更的过渡,但细想一想,还是把这一块从始致终的说清楚。在上一篇文章中JVM系列之Java内存结构详解讲到方法区时提到,JDK7环境下方法区包括了(运行时常量池),其实这么说是不准确的。因为从JDK7开始,HotSpot团队就想到开始去"永久代",大家首先明确一个概念,方法区和"永久代"(PermGen space)是两个概念,方法区是JVM虚拟机规范,任何虚拟机实现(J9等)都不能少这个区间,而"永久代"只是HotSpot对方法区的一个实现。为了把知识点列清楚,我还是才用列表的形式:

    JDK7之前(包括JDK7)拥有"永久代"(PermGen space),用来实现方法区。但在JDK7中已经逐渐在实现中把永久代中把很多东西移了出来,比如:符号引用(Symbols)转移到了native heap,运行时常量池(interned strings)转移到了java heap;类的静态变量(class statics)转移到了java heap.

    所以这就是为什么我说上一篇文章中说方法区中包含运行时常量池是不正确的,因为已经移动到了java heap;

    在JDK7之前(包括7)可以通过-XX:PermSize -XX:MaxPermSize来控制永久代的大小.

    JDK8正式去除"永久代",换成Metaspace(元空间)作为JVM虚拟机规范中方法区的实现。

    元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但仍可以通过参数控制:-XX:MetaspaceSize与-XX:MaxMetaspaceSize来控制大小。

    下面作者还是通过一段代码,来不停的创建Class对象,在JDK8中可以看到metaSpace内存溢出:

    /** 作者准备在JDK8下测试方法区,所以设置了Metaspace的大小为固定的8M -XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=8m */

    public class JavaMethodAreaOOM {

    public static void main(String[] args) {

    while (true) {

    Enhancer enhancer = new Enhancer();

    enhancer.setSuperclass(OOMObject.class);

    enhancer.setUseCache(false);

    enhancer.setCallback(new MethodInterceptor() {

    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

    return proxy.invokeSuper(obj, args);

    }

    });

    //无限创建动态代理,生成Class对象

    enhancer.create();

    }

    }

    static class OOMObject {

    }

    }

    在JDK8的环境下将报出异常:

    Exception in thread "main" java.lang.OutOfMemoryError: Metaspace

    这是因为在调用CGLib的创建代理时会生成动态代理类,即Class对象到Metaspace,所以While一下就出异常了。

    提醒一下:虽然我们日常叫"堆Dump",但是dump技术不仅仅是对于"堆"区域才有效,而是针对OOM的,也就是说不管什么区域,凡是能够报出OOM错误的,都可以使用dump技术生成dump文件来分析。

    在经常动态生成大量Class的应用中,需要特别注意类的回收状况,这类场景除了例子中的CGLib技术,常见的还有,大量JSP,反射,OSGI等。需要特别注意,当出现此类异常,应该知道是哪里出了问题,然后看是调整参数,还是在代码层面优化。

    附加-直接内存异常

    直接内存异常非常少见,而且机制很特殊,因为直接内存不是直接向操作系统分配内存,而且通过计算得到的内存不够而手动抛出异常,所以当你发现你的dump文件很小,而且没有明显异常,只是告诉你OOM,你就可以考虑下你代码里面是不是直接或者间接使用了NIO而导致直接内存溢出。

    好了,"JVM系列之实战内存溢出异常"到这里就给大家介绍完了,Have a good day .欢迎留言指错。

    往期入口:

    展开全文
  • 一、修改一下自己的程序/tomcat配置,将内存调小一点容易调试 -XX:+HeapDumpOnOutOfMemoryError -Xms20m -Xmx20m 二、写一个死循环测试 1、 @Test public void memoryTest(){ List<ContractTmpt> ...
  • java 内存溢出排查

    2021-03-19 09:23:47
    测试代码,如下示例:import .../*** @Description 测试内存溢出, 启动时设置参数,最大堆内存为1m, 内存溢出时dump出内存文件 -Xmx1m -XX:+HeapDumpOutOfMemoryError* @Author luzy* @Date 2018/10/5 11:02*/publi...
  • 1、查询gc情况(每1秒钟打印一次gc情况)jstat -gcutil pid 1000:1查询结果含义:S0:幸存区1占用率S1:幸存区2占用率E:Eden区占用率O:老年区占用率M:元数据区(java8,相当于java7及之前的永久代的概念)使用大小ccs:压缩后...
  • java内存泄露、溢出检查方法和工具。 步骤: 1,使用linux命令生存堆栈文件 2,用MemoryAnalyzer.exe工具打开 3,根据工具生成的饼状图可以清晰的找出内存泄漏源
  • 这两天公司的一个程序出现问题,频繁出现内存溢出错误OutOfMemory:GC overhead limit exceeded. 虽然知道这个错误的原因是因为Java虚拟机在频繁进行垃圾回收,使用了98%的时间进行垃圾回收,但是实际回收了不到2%的...
  • 一、问题定位 直接导出了dump文件 ...二 为何发生了内存泄漏 这个问题,就得探究LIVE_SET是个啥东西? 撸了一圈源码后,有以下收获: 1、它是netty的类:io.netty.util.internal.ObjectCleaner 下面的一个
  • Java 内存溢出排查

    2021-03-21 09:31:59
    因此,OOM 的排查及定位是每个 Java 工程师都必备的技能。所遇到的问题在使用 scala 开发的一个 web 服务,在用户使用中,经常出现:java.lang.OutOfMemoryError: Java heap space。而且还束手无策,每次都只能重启...
  • Java内存溢出怎么解决以及相关分析。一、常见的Java内存溢出有以下三种:1. java.lang.OutOfMemoryError: Java heap space —-JVM Heap(堆)溢出JVM在启动的时候会自动设置JVM Heap的值,其初始空间(即-Xms)是物理...
  • 目录首先我们需要掌握什么是内存溢出和内存泄漏内存泄漏:即声明的对象无法被回收,一直存在于内存中,使得占用的内存就像被泄漏消失了一样内存溢出:即剩余可用的内存空间过小,无法分配出下一步工作需要的内存。...
  • java线上内存溢出问题排查步骤

    万次阅读 2019-02-15 11:24:17
    一般线上遇到比较头疼的就是OOM内存溢出问题,我们都会先看错误日志,如果错误日志能够定位出哪个类对象导致内存溢出,那么我们只需要针对问题修改bug就好。但是很多时候我们单凭日志无法定位出内存溢出问题,那么...
  • Java内存泄漏的排查

    千次阅读 2021-09-06 15:06:59
    1.内存溢出 一种通俗的说法。 1、内存溢出:你申请了10个字节的空间,但是你在这个空间写入11或以上字节的数据,出现溢出。 2、内存泄漏:你用new申请了一块内存,后来很长时间都不再使用了(按理应该释放),但是...
  • 项目运行过程中,我们可能会遇到Java内存溢出Out Of Memory。此时我们可以借助内存分析工具MAT(Memory Analyzer Tool),来定位是哪里出现了问题。 一、MAT(Memory Analyzer Tool) 下载地址:Eclipse Memory ...
  • Java内存溢出排查(必看)

    千次阅读 2019-05-17 10:58:44
    因此,OOM的排查及定位是每个Java工程师都必备的技能。 所遇到的问题 在使用scala开发的一个web服务,在用户使用中,经常出现:java.lang.OutOfMemoryError: Java heap space。而且还束手无策,每次都只能重启服务...
  • 本文以最近碰到的一次线上内存溢出的定位、解决问题的方式展开;希望能对碰到类似问题的同学带来思路和帮助。主要从表现-->排查-->定位-->解决 四个步骤来分析和解决问题。表象最近我们生产上的一个应用...
  • COMMAND 10007 bb 20 0 2898m 348m 14m R 100.5 2.2 1:41.31 java 9702 bb 20 0 2898m 348m 14m S 0.0 2.2 0:00.00 java 9705 bb 20 0 2898m 348m 14m S 0.0 2.2 0:06.44 java 9706 bb 20 0 2898m 348m 14m S 0.0 ...
  • java内存溢出分析工具

    2021-03-04 10:09:25
    http://www.cnblogs.com/preftest/archive/2011/12/08/2281322.htmljava内存溢出分析工具:jmap使用实战在一次解决系统tomcat老是内存撑到头,然后崩溃的问题时,使用到了jmap。1 使用命令在环境是linux+jdk1.5以上...
  • Memory Analyzer(MAT)是一款内存分析工具,可以通过该工具打开.hprof文件进行分析内存溢出的原因。 在开始介绍这款工具使用前,先了解一下如何获取.hprof文件,首先我们需要在tomcat.service文件中加入内存溢出的...
  • 性能测试-java内存溢出问题排查

    千次阅读 2018-10-31 12:06:05
    关于内存溢出 网上的资料全是坑,都没有一篇写到点上的,我就发现了个问题,要查一个难点,你得至少结合30篇博客的知识点加上自己的悟性才能搞定一个问题。 首先,你windows本机得安装好java,我这里用的是...
  • Java内存溢出和泄漏的排查

    千次阅读 2019-06-19 10:04:53
    一定是有一个项目在跑着,然后突然变慢了,你才会想到排查内存泄露的问题的。作为小白,写写逻辑,我觉得基本上接触不到这个问题。自己写程序报错OOM,那需要很大的代码错误。 我接触到这个问题是上次项目经理面试...
  • Java内存溢出及分析

    2020-12-22 23:07:51
     java内存有几种:程序计数器,虚拟机栈,方法常量区,堆,本地方法栈,直接内存。既然分析内存溢出,那从这几种内存逐一分析。  1,程序计数器:是一个较小的内存空间,是但钱线程的字节码行号指示器,这个不会...
  • java内存溢出问题调试

    2021-03-08 19:32:28
    java程序时大家一定对一下两条异常并不陌生:java.lang.OutOfMemoryError: Java heap space...好的编码实践可能会大大降低内存溢出的产生。本文并不是写如何规避内存溢出,但是我还是要介绍一下如何能够尽量规避内...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 22,777
精华内容 9,110
关键字:

java内存溢出排查方法

java 订阅