内存溢出怎么解决,电脑内存溢出怎么解决

内存不足是影响生产中Java(和其他JVM语言)应用程序的最常见问题之一。这篇文章解释了如何识别内存不足的问题,并使用一个小程序演示一些工具,电脑内存溢出怎么解决,可以用来找出哪些东西在占用你的内存。

内存不足是影响生产中Java(和其他JVM语言)应用程序的最常见问题之一。这篇文章解释了如何识别内存不足的问题,并使用一个小程序演示一些工具,电脑内存溢出怎么解决,可以用来找出哪些东西在占用你的内存。,

内存问题是Java环境中不幸的一部分。如果您在Java虚拟机(JVM)上运行程序,并且没有看到上面所示的错误,那就算幸运了。对于其他人来说,这类问题太常见了,通常通过增加堆大小或尝试JVM开关的随机排列来解决,直到它们消失。

我们倾向于在JVM中看到这类问题,因为它在固定大小的堆中运行,在JVM第一次启动时设置。作为运行应用程序的人,您需要估计应用程序所需的内存峰值,然后相应地调整JVM堆的大小。这是很难做到的,通常需要一定程度的实验。

更复杂的是,内存不足的问题并不总是显而易见的。如果幸运的话,应用程序在内存不足时会立即崩溃。但正如它经常一瘸一拐地走着,垃圾回收器不断地试图释放一些空间。这通常会导致内存问题被误诊为应用程序性能问题:top报告应用程序JVM的CPU使用率很高,但实际上所有工作都是由垃圾收集器线程完成的。

本文主要讨论两个主题:如何知道何时内存不足,以及如何跟踪应用程序中使用内存的位置。

识别内存不足

如果幸运的话,你知道你的应用程序内存不足,因为它告诉你了。如果在日志文件中看到:

Exception in thread &34; java.lang.OutOfMemoryError: Java heap space

那你就快没内存了。在这一点上,一个流行的选择是尝试使用一个JVM开关来增加JVM堆大小,比如:

-Xmx1g

希望你的问题能解决。这也许是正确的做法!如果正常使用情况下,应用程序的工作集峰值在1GB左右,那么这里没有问题:设置JVM选项,休息一天。

对于那些还在这里的人,我们需要做更多的挖掘。一个很好的起点是使用-verbose:gc JVM开关。这将告诉垃圾回收器在每次垃圾收集运行后记录诊断信息。启用后,您将在控制台(或日志文件)中看到以下行:

每行记录垃圾回收运行的详细信息。标记为GC的行表示JVM年轻代的垃圾收集,而带有完整GC的行表示JVM旧代的垃圾收集。

这里我们不会描述JVM内存管理的完整工作原理,所以这里是简短的版本:年轻一代和老一代是存储对象的不同内存区域,JVM垃圾使用不同的方法收集每个区域。年轻一代垃圾回收器针对许多活得快、死得早的对象进行了优化;老一代垃圾回收器针对寿命较长的对象进行了优化,这些对象更有可能留在周围。对象在第一次被创造的时候是从年轻一代分配的,如果他们活得够长,最终会在老一代那里度过他们的日子,听收音机,抱怨年轻一代。很好。

所以我们倾向于看到更多的GC行而不是完整的GC行,但是它们都告诉我们相同的东西。随机选取一行:

解决方法:手动设置JVM Heap(堆)的大小。   2. java.lang.OutOfMemoryError: PermGen space  --- PermGen space溢出。 PermGen space的全称是Permanent Generation space,是指内存的。

[GC 52082K->44062K(116544K),0.0040520 secs]

这告诉我们,在垃圾收集过程中,年轻一代:

堆开始时使用了52082kb。

垃圾收集运行完成后,它将堆减少到44062KB(释放大约8MB)。

JVM堆的总提交大小为116544KB。

完成垃圾收集运行大约需要4毫秒。

内存不足的问题是什么样子的

当应用程序遇到问题时,您将开始看到相对较多的完整GC消息。这是一个迹象,表明物体在周围停留,填满了老一代人的区域:

人们通常会通过关注箭头左边的数字(堆利用率预收集)来误解垃圾收集日志。请记住,JVM的正常操作模式是累积垃圾,直到达到某个阈值,然后运行垃圾收集器来清除它。

如果我们获取一些垃圾收集日志,并随着时间的推移,在箭头两侧绘制数字(显示垃圾收集之前和之后的堆利用率),则正常的应用程序如下所示:

这里我们看到一个锯齿状的模式,顶部的点表示垃圾收集之前的堆利用率,底部的点表示紧接着的堆利用率。下面的几点很重要:我们看到垃圾收集器成功地释放了内存,并将堆利用率恢复到一个相当一致的基线。

如果我们绘制上面所示的垃圾收集日志行,情况就不那么乐观了:

随着时间的推移,这个应用程序似乎消耗了更多的内存。垃圾回收器在每次运行期间释放的内存有很大的变化,并且每次收集释放的内存较少。

总而言之,如果出现以下情况,您可能会出现内存不足的问题:

在日志中经常看到完整的GC消息;

内存溢出错误的解决方法:一、设置虚拟内存 ①用右键点击桌面上的“计算机”图标,在出现的右键菜单中选择“属性”选项打开“高级系统设置”。在窗口中点击“高级”选项卡,出现高级设置的对话框。②点击“性能”区域的“设置”。

垃圾回收后的利用率随着时间的推移而增长。

如果是这样的话,是时候开始追踪你的内存泄漏了。

查找内存泄漏

在本节中,我们将介绍一些可以用来查找代码中内存泄漏的工具。本着以假乱真的精神,这里有一个捏造的例子!这个例子有两部分:

GibberishGenerator生成器生成长度不等的非常长的gibberish词行。

MemoryLeak检查这些gibberish的行,以找到符合某些标准的第一个“好”单词,并将找到的好单词列表保存在列表中。

代码如下:

import java.util.ArrayList; import java.util.List; import java.util.Iterator; import java.util.Random; public class MemoryLeak { // Generates long lines of gibberish words. static class GibberishGenerator implements Iterator<String> { private int MAX_WORD_LENGTH = 20; private int WORDS_PER_LINE = 250000; private String alphabet = (&34; +&34;); public boolean hasNext() { return true; } public String next() { StringBuffer result = new StringBuffer(); for (int i = 0; i < WORDS_PER_LINE; i++) { if (i > 0) { result.append(&34;); } result.append(generateWord(MAX_WORD_LENGTH)); } return result.toString(); } public void remove() { // not implemented } private String generateWord(int maxLength) { int length = (int)(Math.random() * (maxLength - 1)) + 1; StringBuffer result = new StringBuffer(length); Random r = new Random(); for (int i = 0; i < length; i++) { result.append(alphabet.charAt(r.nextInt(alphabet.length()))); } return result.toString(); } } // A &34; word has as many vowels as consonants and is more than two // letters long. private static String vowels = &34;; private static boolean isGoodWord(String word) { int vowelCount = 0; int consonantCount = 0; for (int i = 0; i < word.length(); i++) { if (vowels.indexOf(word.charAt(i)) >= 0) { vowelCount++; } else { consonantCount++; } } return (vowelCount > 2 && vowelCount == consonantCount); } public static void main(String[] args) { GibberishGenerator g = new GibberishGenerator(); List<String> goodWords = new ArrayList<String>(); for (int i = 0; i < 1000; i++) { String line = g.next(); for (String word : line.split(&34;)) { if (isGoodWord(word)) { goodWords.add(word); System.out.println(&34; + word); break; } } } } }

此代码存在内存泄漏。让我们用一个普通的JVM堆来运行它,看看会发生什么:

$ java -verbose:gc -Xmx64m MemoryLeak ... Found a good word: EDeGOG [Full GC 44032K->32382K(51136K),0.0088630 secs] [GC 39742K->33566K(58368K),0.0027320 secs] [GC 44382K->36990K(58304K),0.0041990 secs] [Full GC 45982K->44686K(58304K),0.0224270 secs] Found a good word: eZjovI [Full GC 51071K->38076K(58304K),0.0059460 secs] [GC 45436K->39228K(58304K),0.0007690 secs] [GC 46588K->40412K(53440K),0.0009190 secs] [Full GC 52380K->42684K(53440K),0.0085100 secs] [Full GC 50044K->42684K(53440K),0.0086750 secs] [Full GC 50044K->42313K(53440K),0.0092640 secs] [Full GC 47351K->42313K(53440K),0.0077370 secs] [GC 42313K->42313K(57984K),0.0008850 secs] [Full GC 42313K->42297K(57984K),0.0151990 secs] Exception in thread &34; java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:2882) at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:100) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:390) at java.lang.StringBuffer.append(StringBuffer.java:224) at MemoryLeak$GibberishGenerator.next(MemoryLeak.java:24) at MemoryLeak.main(MemoryLeak.java:74)

它找到几个单词,然后耗尽内存。让我们看看一些工具来了解更多。

使用Jmap

首先,获取要调试的JVM的进程ID:

$ ps -ef | grep MemoryLeak mst14979 14511 99 13:53 pts/29 00:00:03 java -verbose:gc -Xmx64m MemoryLeak

然后阅读下面的警告并指示jmap附加到该JVM并遍历其堆:

警告:当jmap执行任务时,目标JVM将被挂起,所以不要在人们实际使用的应用程序上这样做!

查看jmap输出的前几行,已经有了一个线索:在我们获取样本时,有952个字符数组占据了64MB JVM堆中的大约37MB。在列表的顶部看到大字符数组通常是一个很好的信号,表明有一些大字符串被存储在某个地方。

运行jmap(或任何命令!)在JVM抛出OutOfMemoryError的确切时刻,是使用-XX:onAutoOfMemoryError JVM开关。您可以这样调用它:

检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能。

java -Xmx64m -XX:OnOutOfMemoryError=&39; MemoryLeak

JVM的进程ID将自动替换为%p占位符。

使用Heap Dumps堆转储

有时候,看到jmap柱状图就足以让您意识到内存泄漏在哪里,如果最上面的条目是您自己的类之一(比如MyBrilliantCacheEntry),那么就诅咒自己,继续前进。但是,不幸的是,空间的最大用户通常是char[]或byte[],因此您所拥有的只是不太有用的信息。

此时,堆转储可能会有所帮助。堆转储提供应用程序内存的静态快照,使用jvisualvm或Eclipse内存分析器等工具MAT,您可以检查堆转储并查看其中的内容。

使用Jmap获取堆转储

jmap工具可以连接到正在运行的JVM并生成堆转储。具体操作方法如下:

解决:1、扩展内存条,或者增大虚拟内存的大小。2、定期使用电脑安全软件进行系统杀毒。3、定期使用电脑安全软件进行垃圾清理。

$ jmap -F -dump:format=b,file=heap.bin 14979 Attaching to process ID 16610,please wait... Debugger attached successfully. Server compiler detected. JVM version is 20.12-b01 Dumping heap to heap.bin ... Heap dump file created

这将生成一个名为堆.bin可以被几种分析工具读取。我们将在下面的部分中了解它的工作原理。

在OutOfMemoryError上获取堆转储

如果可以使用特殊的开关运行JVM,那么每当抛出OutOfMemoryError时,就可以要求它生成堆转储。只需运行JVM:

java -Xmx64m \-XX:+HeapDumpOnOutOfMemoryError \-XX:HeapDumpPath=/tmp/heap.bin\MemoryLeak

与之前一样,这将生成一个名为heap.bin

从核心文件生成堆转储

通常,前两种方法中的一种足以获得堆转储,但这里有一些琐事。如果使用gdb连接到JVM进程:

$ gdb -p 14979 GNU gdb (GDB) 7.4.1-debian ... (gdb)

您可以使用它转储标准的Unix核心文件:

(gdb) gcore Saved corefile core.14979

然后使用jmap从生成的核心文件创建堆转储:

$ jmap -dump:format=b,file=heap.bin `which java` core.14979 Attaching to core core.14979 from executable /usr/local/bin/java,please wait... Debugger attached successfully. Server compiler detected. JVM version is 20.12-b01 Dumping heap to heap.bin ... Finding object size using Printezis bits and skipping over... Heap dump file created

内存溢出怎么解决

对于使用gcore命令生成的核心文件,这也可以在Solaris下工作。

探索堆转储

无论选择哪种方法,现在都应该有一个名为heap.bin包含应用程序出现问题时内存的快照。

内存溢出怎么解决

有几种工具可以用来分析堆转储。如果你觉得老古板的话,javasdk附带了jhat。对转储文件进行如下运行:

$ jhat heap.bin Reading from heap.bin... Dump file created Tue Oct 29 14:19:49 EST 2013 Snapshot read,resolving... Resolving 29974 objects... Chasing references,expect 5 dots..... Eliminating duplicate references..... Snapshot resolved. Started HTTP server on port 7000 Server is ready.

然后浏览到http://localhost:7000/以浏览堆转储。

我们将加载应用程序的堆转储:

单击“文件”菜单

单击“加载”

为“文件类型”选择“堆转储”

导航到您的heap.bin文件

您将看到堆转储在jvisualvm主窗格中打开:

单击Classes选项卡,我们可以看到jmap之前向我们展示的内容:很多char[]实例使用了我们所有的内存。

在这个屏幕上,我们可以深入查看实例本身。双击char[]的条目,您将被转移到Instances选项卡。

内存溢出的常见原因:1、可能是内存加载的数据量过大导致,比如一次提取过多的数据。2、可能是第三方软件bug导致,可以卸载软件。3、可能是启动参数内存值设定的过小,需要重新设置。4、可能是代码存在死循环。内存条购买注意。

在左边列表的顶部,我们看到几个实例,每个实例大约为5MB。这可是一大堆人物资料啊!看右边的窗格可以看到游戏:

qUqCMAzhjybtUitV vgiUVYuTcROHFygG gjoYlXqOhKdQkvOqot gEQlgdcINvhqjxJ ...

jvisualvm向我们展示的是七个大字符串,每个大约为5MB,每个字符串包含许多gibberish的单词。这就是我们需要的线索:程序中的某些东西将gibberish的输入行保存在内存中,阻止垃圾回收器释放它们。

现在您知道了原因,您可能希望返回到原始代码,看看是否可以发现问题。

String line = g.next(); for (String word : line.split(&34;)) { if (isGoodWord(word)) { goodWords.add(word);

可以扩展一条内存,或者增大虚拟内存的大小 下面以在Windows XP下转移虚拟内存所在盘符为例介绍虚拟内存的设置方法: 一、手动设置虚拟内存 在默认状态下,是让系统管理虚拟内存的,但是系统默认设置的管理方式通常比较保守,在自动调节时会造成。

我们把每行(5MB)gibberish,分成单词,检查每个单词,并保留找到的第一行。怎么了?

这实际上是Java的一个好奇心:字符串是不可变的,因此如果两个字符串在幕后共享同一个字符数组也没有什么坏处。事实上,Java使用这种方法很好地提高了获取子字符串的速度。如果我们有两个字符串:

String s1 = &34;; String s2 = &34;.substring(0,5);

然后,可以创建s2,而不需要额外的字符数组:它只存储对s1字符数组的引用,以及适当的偏移量和长度信息,以捕获它是原始字符串的“片段”这一事实。

在我们的代码中,split创建了原始5MB输入行的子字符串,但该子字符串包含对原始输入行字符数组的引用。即使在原始字符串消失很久并被垃圾回收之后,它的字符数组仍然存在于子字符串中!

我们可以通过显式克隆子字符串来修复它:

String line = g.next(); for (String word : line.split(&34;)) { if (isGoodWord(word)) { goodWords.add(new String(word));

从Java1.7Update6开始,字符串行为发生了变化,这样子字符串就不会保留原来的字节数组了。这对我设计的示例来说有点打击,但找到问题的总体方法仍然有效。

如果觉得本文对你有帮助,可以转发关注支持一下

上一篇 2023年01月09 18:40
下一篇 2023年02月03 18:52

相关推荐

  • 怎样下载速算盒子

    速算盒子最新版下载,“互联网+”时代的到来,使得教育行业受到了影响并且发生了巨大的变革,传统的书本已经不是唯一的学习用具,移动互联网的发展改变了课堂模式,融入了更多的新媒体教具,课后作业同样也不再局限

    2023年01月05 258
  • 随行付怎么样,乐刷费率惊人万元扣百五

    得益于智能手机和线上支付的普及,移动支付经过这几年的迅猛发展之后,线上场景的渗透率已高达85%,并维持着“二八分”的竞争局面。在此背景下,支付市场上的微信、支付宝、云闪付等各路玩家纷纷把“战火”引向渗

    2023年01月21 233
  • 小米贷款怎样提额,小米贷款怎么快速提额

    如今,分期购物越来越普遍,尤其是消费金额较大的电子产品,很多人都会选择分期付款。分期乐是一款面向年轻人提供分期消费的金融服务平台,是中国分期购物电商模式开创者。本文作者对其进行了拆解分析,希望对你有帮

    2023年01月05 265
  • 怎样建立微信,如何建立一个微信群

    不知道机友们还记不记得,早在去年10月份,就有媒体曝光了微信将推出「微信小号」的消息。如今时隔近一年,这个功能终于是正式开启了内测。添加的方法也不复杂,如果是被内测到的用户,如何建立一个微信群,那现在

    2023年01月05 297
  • b站怎么私信

    上期小编给大家介绍了哔哩哔哩工会怎么入驻,平台要求也是比较严格的,那现在新政策具体有哪些要求?一、入驻哔哩哔哩工会新政策要求。营业执照,拥有合规营业执照。注册资金≥10万元。具备直播行业要求的相关公司

    2023年02月05 289
  • 虎课网怎么样

    人到中年负担重,也没有多少时间用于学习,但如今竞争越来越大,虎课是骗局吗,如果自己没有特长,怎么能在人群中脱颖而出?今天给大家推荐7个适合中年人的自学网站,每天学一点,坚持半年让你摆脱现状。一、虎课网

    2023年02月01 268
  • 打印机怎么扫描身份证,打印机怎么扫描身份证原件

    有很多的小伙伴经常会需要用到电子版的证件照,打印机怎么扫描身份证原件,尤其是办一些工作或政务方面的文件时会经常需要使用到。其中使用手机制作身份证扫描件的方法有很多的用户不知道有哪些。今天就给大家推荐两

    2023年01月20 285
  • 菜鸟驿站怎么赚钱,新手做京东快递员难做吗

    新手做京东快递员难做吗,推荐语:这些年来,我国迎来了互联网发展的高速时代。而在庞大的互联网行业中,网购作为新兴的行业,在崛起后彻底改变了我们的生活方式,也间接带动了物流、电子支付行业的发展。但是另一方

    2023年01月09 204
  • 怎样隐藏应用软件,免费的隐藏应用软件

    相信每个人的手机里都会藏有自己的小秘密,当然,免费的隐藏应用软件,我们也不希望自己的App在使用的时候被发现,那么我们如何将自己的不想被别人看到的App隐藏起来呢?今天就教大家如何用三星手机隐藏自己的

    2023年01月02 223
  • word怎么搜索

    引入了一个全新的搜索栏。现在,用户可以在文档中更轻松地查找内容,输入更多选项,还可以在结果中导航。我们来看看如何在Word文档中查找和替换文本。如何在Word文档中查找单词或短语如要在文档中查找单独的

    2023年02月04 226
  • 怎么更新bios,华硕怎么更新bios

    英特尔第11代台式机处理器读者朋友们有用上了的吗?由于这一代采用的是全新的架构设计,因此在上市初期这几个月当中,主板厂商肯定会对这一代处理器乃至整套平台进行大幅优化的。也因此,对于广大用户们来说,通过

    2023年02月04 203
  • 怎样建自己的博客,怎么建立一个自己的博客

    怎么建立一个自己的博客,您可能想知道成为一个专业的博主是什么样子,但问题是您不知道如何写博客。您只能想到那些好处:设定自己的工作时间,做自己的老板,可以穿着睡衣在家里工作。但&34;这一部分仍然让很多

    2023年01月03 262
  • 网易云怎么发动态,新版网易云怎么发纯文字动态

    一、引言去年梳理了QQ音乐APP的迭代分析之后,因为音乐版权的问题,连续开了半年的QQ音乐会员,已经很少使用网易云音乐来听歌了,偶尔听民谣的时候才会想起来,以及无意中发现的“一起听”功能,体验了几次觉

    2023年01月19 264
关注微信