OOM

一次OOM的排查过程

醉酒当歌 提交于 2019-12-17 10:38:12
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 最近测试环境的Java应用经常挂掉,用jconsole查看堆内存使用情况,如下图: 在达到高峰的时候tomcat服务挂了,看图可以知道使用内存过大,于是开始追踪元凶。 加入启动参数 在catalina.sh加入-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/web/tomcat7/temp/oom.hprof 第一个参数是当发生OOM是生成heap dump文件,第二个参数是指定文件路径 MAT工具分析 将生成的oom.hprof载入MAT进行分析(MAT工具下载地址: 迅雷下载链接 ),如下图: 工具怎么使用在此不讲了,参考官网wiki介绍。 点击图中Reports 下的 Leak Suspects,这里会列出了工具怀疑的内存泄露点,不过工具怀疑的也未必真的是存在的,但提供了一种参考。如下图: 图中怀疑内存泄漏点有四处,点击图中第一处的details查看详细情况,如下图: 从图中可以看到一个ArrayList有240097个对象引用没有释放掉,这才是导致OOM的原因,再查看报告中的Thread Stack,找到具体代码所在处,如下图: 经过排查,原来是程序代码一次性从数据库加载了全部的数据,没有分页导致的,修改完代码后一切正常了~~ 来源:

android viewHolder处理listView滑动

风流意气都作罢 提交于 2019-12-15 17:44:07
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 在没有用viewHolder的情况下,listView表现效率低下。如果加载的数量过多则会一点点的消耗内存,直到抛出oom。开始异步加载图片会出现图片错位的问题,后来查阅资料将holder里边的图片地址和图片一一对应起来,在异步加载的回调函数中将其替换回来。 holder.thumb_image.setTag(hotel.getHotelTitlePic()); //避免图标错位,在异步加载成功后替换回来 ImageView imageView = (ImageView) listView.findViewWithTag(imageUrl); if(imageView != null){ imageView.setImageDrawable(imageDrawable); imageView.setTag(""); } 以上关键代码解决图片错位问题。 下面是getView()方法 public View getView(int position, View rowView, ViewGroup parent){ final MHotelInfo hotel = this.getItem(position); if (rowView == null) { holder = new ViewHolder();

Android中如何避免OOM

血红的双手。 提交于 2019-12-10 08:19:48
手机内存比较小,随时可能发生溢出的情况,所以避免内存泄露非常重要,否则程序二话不说直接崩溃。。下面的内容总结一下自己的经验以及学习成果。有错误或者有补充的欢迎跟帖讨论。 1.避免对activity的超过生命周期的引用。(尽量使用application代替activity)。因为程序一般是由很多个Activity构成的,从一个Activity跳转了以后,系统就有可能回收这个Activity的各种内存占用。可是此时如果你的一些不可回收变量(比如静态变量)保持了对此Activity对象的引用,那么GC就不会对此Activity进行回收,无故占用了大量的内存。这种情况最好的办法就是用application代替activity。用Context.getApplicationContext() 或者 Activity.getApplication()可以很方便的得到application对象。具体参考帖子 http://www.eoeandroid.com/forum.php?mod=viewthread&tid=173353 2.有些不得不缓存在内存中的图片大字符串等,最好使用软引用或者弱引用。最经典的例子就是异步下载图片,图片会保存到一个HashMap中,下载一张就保存一张到HashMap中。此时hashmap中图片越来越多内存就容易不够用。软引用很好的解决了这个问题。当系统内存不足时

KJFrameForAndroid框架学习----高效加载Bitmap

别说谁变了你拦得住时间么 提交于 2019-12-07 14:57:12
欢迎各位加入我的Android开发群 [ 257053751 ] KJFrameForAndroid框架项目地址: https://github.com/kymjs/KJFrameForAndroid 我们在写Android程序的时候,肯定会用到很多图片。那么对于图片的压缩处理自然是必不可少。为什么要压缩?我想这个问题不必在强调了,每个人在最初学习Android的时候肯定都会知道这么一个原因:我们编写的应用程序都是有一个最大内存限制,其中JAVA程序和C程序(NDK调用时)共享这一块内存大小,程序占用了过高的内存就容易出现OOM(OutOfMemory)异常。至于这个最大内存是多少,我们可以通过调用Runtime.getRuntime().maxMemory()方法验证一下。 正因为受到内存大小限制这一关键原因(其实不止这个原因,我想一张1M的图片和一张10k的图片,载入的速度必然也是不同的吧)。 如果你的控件大小只有40*40像素的大小,只是为了显示一张缩略图,这时候把一张1024*768像素的图片完全加载到内存中显然是不值得的,因此我们都会对图片做压缩处理。 BitmapFactory这个类提供了多个方法(decodeByteArray, decodeFile, decodeResource等)用于创建Bitmap对象,我们可以根据图片的来源选择合适的方法

Android的内存泄漏和调试

人走茶凉 提交于 2019-12-02 08:54:47
一、 Android的内存机制 Android的程序由Java语言编写,所以Android的内存管理与Java的内存管理相似。程序员通过new为对象分配内存,所有对象在java堆内分配空间;然而对象的释放是由垃圾回收器来完成的. 那么GC怎么能够确认某一个对象是不是已经被废弃了呢?Java采用了有向图的原理。Java将引用关系考虑为图的有向边,有向边从引用者指向引用对象。 线程对象可以作为有向图的起始顶点,该图就是从起始顶点开始的一棵树,根顶点可以到达的对象都是有效对象,GC不会回收这些对象。如果某个对象 (连通子图)与这个根顶点不可达(注意,该图为有向图),那么我们认为这个(这些)对象不再被引用,可以被GC回收。 二、Android的内存溢出 Android的内存溢出是如何发生的? Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的机器为24M。因此我们所能利用的内存空间是有限的。如果我们的内存占用超过了一定的水平就会出现OutOfMemory的错误。 为什么会出现内存不够用的情况呢?我想原因主要有两个: 由于我们程序的失误,长期保持某些资源(如Context)的引用,造成内存泄露,资源造成得不到释放。 保存了多个耗用内存过大的对象(如Bitmap),造成内存超出限制。 三、常见的内存泄漏 1.万恶的static

【构建Android缓存模块】(三)Controller & 异步图片加载

こ雲淡風輕ζ 提交于 2019-12-01 19:43:26
转 载 声明: Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-) http://my.oschina.net/ryanhoo/blog/93432 上 节课 我们学习了缓存模块的实现, 缓存分做两份: Memory Cache 和 File Cache 。方法也很简单,分别是: 存储文件 按唯一key值索引文件 清空缓存 区别在于内存缓存读取优先,因为它读写的速度更快。但是考虑到内存限制,退而选用文件存储,分担内存缓存的压力。 原理非常简单,在第一课中已经详细分析了。那么要怎么才能将这个缓存模块与UI模块的显示关联起来呢?在这里我们需要一个控制器,掌管数据流向和读写,同时控制UI的显示。 那么这个控制器需要以下的元素: 内存缓存 硬盘缓存 异步任务处理 控制UI显示 //caches private MemoryCache memoryCache; private FileCache fileCache; //Asynchronous task private static AsyncImageLoader imageLoader; Memory Cache 和 File Cache 在上一课中有具体的实现,这里有一个异步的任务处理器—— AsyncImageDownloader ,它用来在后台下载数据,完成下载后存储数据到缓存中

【构建Android缓存模块】(二)Memory Cache & File Cache

北城余情 提交于 2019-11-30 15:27:35
转 载 声明: Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-) http://my.oschina.net/ryanhoo/blog/93406 上 节课 我们讲到普通应用缓存Bitmap的实现分析,根据MVC的实现原理,我将这个简单的缓存实现单独写成一个模块,这样可以方便以后的使用,对于任意的需求,都属于一个可插拔式的功能。 之前提到,这个缓存模块主要有两个子部件: Memory Cache :内存缓存的存取速度非常惊人,远远快于文件读取,如果没有内存限制,当然首选这种方式。遗憾的是我们有着 16M 的限制(当然大多数设备限制要高于Android官方说的这个数字),这也正是大Bitmap容易引起OOM的原因。 Memory Cache 将使用 WeakHashMap 作为缓存的中枢,当程序内存告急时,它会主动清理部分弱引用(因此,当引用指向为null,我们必须转向硬盘缓存读取数据,如果硬盘也没有,那还是重新下载吧)。 能力越大,责任越大?人家只是跑得快了点儿,总得让人家休息,我们一定不希望让内存成为第一位跑完马拉松的 Pheidippides ,一次以后就挂了吧?作为精打细算的猿媛,我们只能将有限的内存分配给 Memory Cache , 将更繁重的任务托付给任劳任怨的 SDCard 。 File Cache :硬盘读取速度当然不如内存

【Google官方教程】第三课:缓存Bitmap

↘锁芯ラ 提交于 2019-11-29 12:37:40
转 载 声明: Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-) http://my.oschina.net/ryanhoo/blog/88443 译者: Ryan Hoo 来源: https://developer.android.com/develop/index.html 译者按: 在Google最新的文档中,提供了一系列含金量相当高的教程。因为种种原因而鲜为人知,真是可惜!Ryan将会细心整理,将之翻译成中文,希望对开发者有所帮助。 本系列是Google关于展示大Bitmap(位图)的官方演示,可以有效的解决内存限制,更加有效的加载并显示图片,同时避免让人头疼的OOM(Out Of Memory)。 ------------------------------------------------------------------------------------- 译文: 加载一个Bitmap(位图)到你的UI界面是非常简单的,但是如果你要一次加载一大批,事情就变得复杂多了。在大多数的情况下(如ListView、GridView或者ViewPager这样的组件),屏幕上的图片以及马上要在滚动到屏幕上显示的图片的总量,在本质上是不受限制的。 像这样的组件在子视图移出屏幕后会进行视图回收,内存使用仍被保留

【Google官方教程】第四课:在UI中显示Bitmap

落花浮王杯 提交于 2019-11-29 12:36:59
转 载 声明: Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-) http://my.oschina.net/ryanhoo/blog/88484 译者: Ryan Hoo 来源: https://developer.android.com/develop/index.html 译者按: 在Google最新的文档中,提供了一系列含金量相当高的教程。因为种种原因而鲜为人知,真是可惜!Ryan将会细心整理,将之翻译成中文,希望对开发者有所帮助。 本系列是Google关于展示大Bitmap(位图)的官方演示,可以有效的解决内存限制,更加有效的加载并显示图片,同时避免让人头疼的OOM(Out Of Memory)。 ------------------------------------------------------------------------------------- 译文: 这节课将我们前面几节课学习的东西都整合起来,向你展示如何使用后台线程和Bitmap缓存加载多个Bitmap(位图)到ViewPager和GridView组件中,并学习如何处理并发和配置变化问题。 实现加载Bitmap到ViewPager 滑动浏览模式( Swipe View Pattern )是一种很好的浏览详细图片的方式。你可以使用 ViewPager

Thrift Direct Memory OOM问题解决方法

非 Y 不嫁゛ 提交于 2019-11-28 22:49:31
FrameBuffer为AbstractNonblockingServer类的内部类,TThreadedSelectorServer继承了AbstractNonblockingServer: 通过研究代码,发现FrameBuffer的read方法的代码中有如下片段, // pull out the frame size as an integer. int frameSize = buffer_.getInt(0); if (frameSize <= 0) { LOGGER.error("Read an invalid frame size of " + frameSize + ". Are you using TFramedTransport on the client side?"); return false; } // if this frame will always be too large for this server, log the // error and close the connection. if (frameSize > MAX_READ_BUFFER_BYTES) { LOGGER.error("Read a frame size of " + frameSize + ", which is bigger than the maximum