当前位置: 首页 > 科技观察

Android内存不足(OutofMemory)方法总结

时间:2023-03-12 06:26:35 科技观察

避免内存溢出的方法主要是在以下三个方面对程序进行优化References、WeakReferences、PhantomReferencesStrongReferences:强引用是最常用的引用。如果一个对象有强引用,垃圾收集器将永远不会收集它。当内存空间不足时,Java虚拟机宁可抛出OutOfMemoryError错误导致程序异常终止,也不会通过强引用对象的任意回收来解决内存不足的问题。软引用:如果一个对象只有软引用,但内存空间足够,垃圾回收器不会回收它;直到虚拟机报告内存不够时才会回收。只要垃圾收集器不回收它,该对象就可以被回收程序使用。软引用可用于实现对内存敏感的缓存。软引用可以与引用队列(ReferenceQueue)结合使用。如果软引用引用的对象被垃圾回收器回收,Java虚拟机会将软引用添加到与其关联的引用队列中。弱引用:仅具有弱引用的对象的生命周期较短。在垃圾回收线程扫描其管辖内存区域的过程中,一旦发现只有弱引用的对象,无论当前内存空间是否足够,都会回收其内存。然而,由于垃圾收集器是一个非常低优先级的线程,只有弱引用的对象可能无法快速找到。弱引用可以与引用队列(ReferenceQueue)结合使用。如果弱引用引用的对象被垃圾回收,Java虚拟机会将弱引用添加到与其关联的引用队列中。幻引用:幻引用可以理解为假引用。与其他类型的引用不同,幻象引用不决定对象的生命周期。如果一个对象只持有虚引用,就好像它没有引用一样,随时可能被垃圾收集器回收。幻象引用主要用于跟踪被垃圾收集器回收的对象的活动。幻影引用与软引用和弱引用的区别之一是幻影引用必须与引用队列(ReferenceQueue)结合使用。当垃圾回收器要回收一个对象时,如果发现它还有一个虚引用,就会把这个虚引用添加到与之关联的引用队列中,然后再回收该对象的内存。程序可以通过判断引用队列中是否加入了幻引用来获知被引用对象是否会被垃圾回收。如果程序发现引用队列中加入了虚引用,则可以在被引用对象的内存被回收之前采取必要的动作。1、释放强引用一般我们在声明对象变量的时候,用完之后就不用管了。我们认为垃圾收集器会帮我们回收这些对象指向的内存空间。事实上,如果这个对象的内存空间还处于被引用状态的话,垃圾回收器是永远不会回收它的内存空间的。只有当这块内存空间没有被任何对象引用时,垃圾收集器才会回收它。所以我们在使用完对象后,可以将对象设置为空,这样我的垃圾回收器gc就会在合适的时候释放为对象分配的内存空间Objectobj=newObject();obj=null;当然在Set中它到***以确认是否不再需要该对象。如果您需要随时使用此对象,则不能这样做。2、使用软引用会在jvm报告内存不足之前清除所有的软引用,所以gc可以收集很多软引用释放的内存空间,解决内存不足的问题,避免内存溢出。什么时候回收取决于gc的算法和gc运行时可用内存的大小。我们可以使用SoftReference来封装强引用对象Stringstr="zhuwentao";//强引用SoftReferencestrSoft=newSoftReference(str);//使用软引用来封装强引用3.使用弱引用来收集弱引用被引用对象的执行过程和软引用是一样的,只是gc不会根据内存情况决定是否回收弱引用对象。Stringstr="zhuwentao";//强引用Wea??kReferencestrWeak=newWeakReference(str);//使用弱引用来封装强引用如果你希望能够随时获取某个对象的信息,但是不想影响对象的垃圾回收,应该使用WeakReference来记住对象,而不是一般的Reference。图像处理中的大部分OOM发生在图像加载时。当我们加载大图片时,需要特别注意避免OOM。在处理大图片时,不管你的手机内存有多大,如果不对图片进行处理,都可能会出现内存溢出。因为Android系统会为每个应用程序分配一定的内存,并不会把系统内存全部分配给应用程序,所以不管你的手机有多少内存,对于每个App来说,它能使用的内存都是有限的。这一点和PC端有很大的不同。如果PC端内存不够,可以请求使用虚拟内存,但是Android系统没有这个机制。1.压缩内存中的图片加载大图片时,需要对图片进行压缩,使用等比压缩的方法直接在内存中处理图片。Optionsoptions=newBitmapFactory.Options();options.inSampleSize=5;//原图的五分之一,如果设置为2,则为二分之一BitmapFactory.decodeFile(myImage.getAbsolutePath(),options);需要注意的是画面质量会变差。SampleSize中设置的值越大,图片的质量越差,不同的手机厂商可能有不同的缩放比例。2.使用图片后回收图片占用的内存。因为Android的外层使用java,底层使用C语言为内层的图像对象分配的内存空间。所以我们的外表虽然看起来释放了,但内层却不一定完全释放。当我们使用完图片后,我们最终会释放内层的内存空间。if(!bitmapObject.isRecyled()){//Bitmap对象没有被回收bitmapObject.recycle();//释放System.gc();//提醒系统及时回收}3.降低颜色质量AndroidBitmap中显示的图片有四种图片颜色模式:ALPHA_8:每个像素需要占用内存1byteRGB_565:每个像素需要占用内存2byteARGB_4444:每个像素需要占用内存2byteARGB_8888:每个像素需要占用内存4bytesinmemory创建Bitmap时,默认的颜色模式是ARGB_8888。这种颜色模式质量最高,当然这种模式占用的内存也是最大的。但是ARGB_4444的每个像素只占用2个字节,所以使用ARGB_4444模式也可以减少图像占用的内存大小。BitmapFactory.Optionsoptions=newBitmapFactory.Options();options.inPreferredConfig=Bitmap.Config.ARGB_4444;BitmapbtimapObject=BitmapFactory.decodeFile(myImage.getAbsolutePath(),o其实大部分图片都设置成ARGB_4444模式,在上面看不到display和ARGB_8888模式有什么区别,只是当图片有渐变色效果时,渐变色可能会出现彩条的效果,这种降低色质的方法在降低内存上不如方法一有效.4.查询图片信息不要把图片加载到内存中有时候我们获取一张图片,可能只是为了获取图片的一些信息,比如图片的宽高等信息,这些是不需要的显示在界面上。此时,我们不能将图片加载到内存中。ory.decodeFile(myImage.getAbsolutePath(),options);在JustDecodeBounds属性中,如果值为true,则不会返回实际的Bitmap对象,也不会为其分配内存空间,但可以让我们查询基本的图像的宽度、高度和大小等信息。(获取原始宽高:options.outWidth,options.outHeight)VMRuntimeVMRuntime是AndroidSDK中提供的类。只在Android2.3之前有用,2.3之后的SDK不支持,所以这个VMRuntime不通用。这里简单介绍一下。1.优化Dalvik虚拟机的堆内存分配VMRuntime类提供的setTargetHeapUtilization方法可以提升程序堆内存的处理效率。privatefinalstaticfloatTARGET_HEAP_UTILIZATION=0.75f;VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);2.Customheapmemorysize定义Android分配给当前App的内存大小,使用VMRuntime设置应用的最小堆内存。//设置最小堆内存为6MBprivatefinalstaticintHEAP_SIZE=6*1024*1024;VMRuntime.getRuntime().setMinimumHeapSize(HEAP_SIZE);largeHeap允许Dalvik虚拟机为App分配更多的内存,这个方法可以为我们的App赢得更多内存空间,从而缓解内存不足的压力。可以在程序中使用ActivityManager.getMemoryClass()方法获取App正常使用情况下的内存大小。通过ActivityManager.getLargeMemoryClass()可以获取启用largeHeap时的最大内存大小。1.使用方法该方法使用非常简单,只需在AndroidManifest中的节点属性中添加"android:largeHeap="true""2.注意,Dalvik给我们的App增加的内存很可能是通过杀掉其他后台进程获得的。这种方法对于开发人员来说是不道德的。我们不应该把解决OOM问题的方法寄托在最好的内存上。我们应该通过合理的代码编写,尽量避免OOM问题。