当前位置:  编程技术>移动开发
本页文章导读:
    ▪施用MAT分析内存泄漏(一)        使用MAT分析内存泄漏(一) 前言   在平时工作过程中,有时会遇到 OutOfMemoryError ,我们知道遇到 Error 一般表明程序存在着严重问题,可能是灾难性的。所以找出是什么原因造成 OutOfMemoryE.........
    ▪ 反编译apk资料方法        反编译apk文件方法 1.首先找到Android软件安装包中的class.dex     把apk文件改名为.zip,然后解压缩其中的class.dex文件,它就是java文件编译再通过dx工具打包成的,所以现在我们就用上述提到的2.........
    ▪ 简略拍照,多媒体图片文件夹中选择图片       简单拍照,多媒体图片文件夹中选择图片 1.button.setOnClickListener(new OnClickListener(){                  @Override           public void onClick(View arg0) {                       Inte.........

[1]施用MAT分析内存泄漏(一)
    来源: 互联网  发布时间: 2014-02-18
使用MAT分析内存泄漏(一)

前言

 

在平时工作过程中,有时会遇到 OutOfMemoryError ,我们知道遇到 Error 一般表明程序存在着严重问题,可能是灾难性的。所以找出是什么原因造成 OutOfMemoryError 非常重要。现在向大家引荐 Eclipse Memory Analyzer tool(MAT) ,来化解我们遇到的难题。如未说明,本文均使用 Java 5.0 on Windows XP SP3 环境。

 

为什么用 MAT

 

之前的观点,我认为使用实时 profiling/monitoring 之类的工具,用一种非常实时的方式来分析哪里存在内存泄漏是很正确的。年初使用了某 profiler 工具测试消息中间件中存在的内存泄漏,发现在吞吐量很高的时候 profiler 工具自己也无法响应,这让人很头痛。后来了解到这样的工具本身就要消耗性能,且在某些条件下还发现不了泄漏。所以,分析离线数据就非常重要了, MAT 正是这样一款工具。

 

为何会内存溢出

 

我们知道 JVM 根据 generation( 代 ) 来进行 GC ,根据下图所示,一共被分为 young generation( 年轻代 ) 、 tenured generation( 老年代 ) 、 permanent generation( 永久代 , perm gen) , perm gen (或称 Non-Heap 非堆)是个异类,稍后会讲到。注意, heap 空间不包括 perm gen 。

绝大多数的对象都在 young generation 被分配,也在 young generation 被收回,当 young generation 的空间被填满, GC 会进行 minor collection( 次回收 ) ,这次回收不涉及到 heap 中的其他 generation , minor collection 根据 weak generational hypothesis( 弱年代假设 ) 来假设 young generation 中大量的对象都是垃圾需要回收, minor collection 的过程会非常快。 young generation 中未被回收的对象被转移到 tenured generation ,然而 tenured generation 也会被填满,最终触发 major collection( 主回收 ) ,这次回收针对整个 heap ,由于涉及到大量对象,所以比 minor collection 慢得多。

 

JVM 有三种垃圾回收器,分别是 throughput collector ,用来做并行 young generation 回收,由参数 -XX:+UseParallelGC 启动; concurrent low pause collector ,用来做 tenured generation 并发回收,由参数 -XX:+UseConcMarkSweepGC 启动; incremental low pause collector ,可以认为是默认的垃圾回收器。不建议直接使用某种垃圾回收器,最好让 JVM 自己决断,除非自己有足够的把握。

 

Heap 中各 generation 空间是如何划分的?通过 JVM 的 -Xmx=n 参数可指定最大 hea p 空间,而 -Xms=n 则是指定 最小 heap 空间。在 JVM 初始化的时候,如果最小 heap 空间小于最大 heap 空间的话,如上图所示 JVM 会把未用到的空间标注为 Vi rtual 。除了这两个参数还有 -XX:MinHeapFreeRatio=n 和 -XX:MaxHeapFreeRatio=n 来分别控制最大、最小的剩余空间与活动对象之比例。在 32 位 Solaris SPARC 操作系统下,默认值如下,在 32 位 windows xp 下,默认值也差不多。


参数

默认值

MinHeapFreeRatio

40

MaxHeapFreeRatio

70

-Xms

3670k

-Xmx

64m


由于 tenured generation 的 major collection 较慢,所以 tenured generation 空间小于 young generation 的话,会造成频繁的 major collection ,影响效率。 Server JVM 默认的 young generation 和 tenured generation 空间比例为 1:2 ,也就是说 young generation 的 eden 和 survivor 空间之和是整个 heap (当然不包括 perm gen )的三分之一,该比例可以通过 -XX:NewRatio=n 参数来控制,而 Client JVM 默认的 -XX:NewRatio 是 8 。至于调整 young generation 空间大小的 NewSize=n 和 MaxNewSize=n 参数就不讲了,请参考后面的资料。

 

young generation 中幸存的对象被转移到 tenured generation ,但不幸的是 concurrent collector 线程在这里进行 major collection ,而在回收任务结束前空间被耗尽了,这时将会发生 Full Collections(Full GC) ,整个应用程序都会停止下来直到回收完成。 Full GC 是高负载生产环境的噩梦 ……

 

现在来说说异类 perm gen ,它是 JVM 用来存储无法在 Java 语言级描述的对象,这些对象分别是类和方法数据(与 class loader 有关)以及 interned strings( 字符串驻留 ) 。一般 32 位 OS 下 perm gen 默认 64m ,可通过参数 -XX:MaxPermSize=n 指定, JVM Memory Structure 一文说,对于这块区域,没有更详细的文献了,神秘。

 

回到问题“为何会内存溢出?”。

要回答这个问题又要引出另外一个话题,既什么样的对象 GC 才会回收?当然是 GC 发现通过任何 reference chain( 引用链 ) 无法访问某个对象的时候,该对象即被回收。名词 GC Roots 正是分析这一过程的起点,例如 JVM 自己确保了对象的可到达性 ( 那么 JVM 就是 GC Roots) ,所以 GC Roots 就是这样在内存中保持对象可到达性的,一旦不可到达,即被回收。通常 GC Roots 是一个在 current thread( 当前线程 ) 的 call stack( 调用栈 ) 上的对象(例如方法参数和局部变量),或者是线程自身或者是 system class loader( 系统类加载器 ) 加载的类以及 native code( 本地代码 ) 保留的活动对象。所以 GC Roots 是分析对象为何还存活于内存中的利器。 知道了什么样的对象 GC 才会回收后,再来学习下对象引用都包含哪些吧。

 

从最强到最弱,不同的引用(可到达性)级别反映了对象的生命周期。

l  Strong Ref( 强引用 ) :通常我们编写的代码都是 Strong Ref ,于此对应的是强可达性,只有去掉强可达,对象才被回收。

l  Soft Ref( 软引用 ) :对应软可达性,只要有足够的内存,就一直保持对象,直到发现内存吃紧且没有 Strong Ref 时才回收对象。一般可用来实现缓存,通过 java.lang.ref.SoftReference 类实现。

l  Weak Ref( 弱引用 ) :比 Soft Ref 更弱,当发现不存在 Strong Ref 时,立刻回收对象而不必等到内存吃紧的时候。通过 java.lang.ref.WeakReference 和 java.util.WeakHashMap 类实现。

l  Phantom Ref( 虚引用 ) :根本不会在内存中保持任何对象,你只能使用 Phantom Ref 本身。一般用于在进入 finalize() 方法后进行特殊的清理过程,通过 java.lang.ref.PhantomReference 实现。

 

有了上面的种种我相信很容易就能把 heap 和 perm gen 撑破了吧,是的利用 Strong Ref ,存储大量数据,直到 heap 撑破;利用 interned strings (或者 class loader 加载大量的类)把 perm gen 撑破。

 

关于 shallow size 、 retained size

 

Shallow size 就是对象本身占用内存的大小,不包含对其他对象的引用,也就是对象头加成员变量(不是成员变量的值)的总和 。在 32 位系统上,对象头占用 8 字节, int 占用 4 字节,不管成员变量(对象或数组)是否引用了其他对象(实例)或者赋值为 null 它始终占用 4 字节。故此,对于 String 对象实例来说,它有三个 int 成员( 3*4=12 字节)、一个 char[] 成员( 1*4=4 字节)以及一个对象头( 8 字节),总共 3*4 +1*4+8=24 字节。根据这一原则,对 String a=”rosen jiang” 来说,实例 a 的 shallow size 也是 24 字节(很多人对此有争议,请看官甄别并留言给我) 。

 

Retained size 是该对象自己的 shallow size ,加上从该对象能直接或间接访问到对象的 shallow size 之和。换句话说, retained size 是该对象被 GC 之后所能回收到内存的总和 。为了更好的理解 retained size ,不妨看个例子。

 

把内存中的对象看成下图中的节点,并且对象和对象之间互相引用。这里有一个特殊的节点 GC Roots ,正解!这就是 reference chain 的起点。

从 obj1 入手,上图中蓝色节点代表仅仅只有通过 obj1 才能直接或间接访问的对象。因为可以通过 GC Roots 访问,所以左图的 obj3 不是蓝色节点;而在右图却是蓝色,因为它已经被包含在 retained 集合内。

所以对于左图, obj1 的 retained size 是 obj1 、 obj2 、 obj4 的 shallow size 总和;右图的 retained size 是 obj1 、 obj2 、 obj3 、 obj4 的 shallow size 总和 。 obj2 的 retained size 可以通过相同的方式计算。

 

Heap Dump

 

heap dump 是特定时间点, java 进程的内存快照 。有不同的格式来存储这些数据,总的来说包含了快照被触发时 java 对象和类在 heap 中的情况。由于快照只是一瞬间的事情,所以 heap dump 中无法包含一个对象在何时、何地(哪个方法中)被分配这样的信息。

 

在不同平台和不同 java 版本有不同的方式获取 heap dump ,而 MAT 需要的是 HPROF 格式的 heap dump 二进制文件。想无需人工干预的话,要这样配置 JVM 参数: -XX:-HeapDumpOnOutOfMemoryError ,当错误发生时,会自动生成 heap dump ,在生产环境中,只有用这种方式。如果你想自己控制什么时候生成 heap dump ,在 Windows+JDK6 环境中可利用 JConsole 工具,而在 Linux 或者 Mac OS X 环境下均可使用 JDK5 、 6 自带的 jmap 工具。当然,还可以配置 JVM 参数: -XX:+HeapDumpOnCtrlBreak ,也就是在控制台使用 Ctrl+Break 键来生成 heap dump 。由于我是 windows+JDK5 ,所以选择了 -XX:-HeapDumpOnOutOfMemoryError 这种方式,更多配置请参考 MAT Wiki 。

 

参考资料

 

MAT Wiki

Interned Strings

Strong,Soft,Weak,Phantom Reference

Tuning Garbage Collection with the 5.0 Java[tm] Virtual Machine

Permanent Generation

Understanding Weak References译文

Java HotSpot VM Options

Shallow and retained sizes

JVM Memory Structure

GC roots

 

请注意!引用、转贴本文应注明原作者:Rosen Jiang 以及出处: http://www.blogjava.net/rosen


    
[2] 反编译apk资料方法
    来源: 互联网  发布时间: 2014-02-18
反编译apk文件方法

1.首先找到Android软件安装包中的class.dex
    把apk文件改名为.zip,然后解压缩其中的class.dex文件,它就是java文件编译再通过dx工具打包成的,所以现在我们就用上述提到的2个工具来逆方向导出java源文件;
2.把class.dex拷贝到dex2jar.bat所在目录。 (http://www.my400800.cn )
    运行dex2jar.bat classes.dex

   生成classes_dex2jar.jar
3.运行JD-GUI工具(它是绿色无须安装的)
    打开上面的jar文件,即可看到源代码
    俺也是今天才试验了下效果,那是相当的凑效,所以兄弟姐妹们觉着好就给句鼓励的话
4 用AXMLPrinter反编译xml文件:

    java -jar AXMLPrinter2.jar AndroidManifest.xml -> AndroidManifest2.xml

AXMLPrinter的下载地址如下:

    http://android4me.googlecode.com/files/AXMLPrinter2.jar

    
[3] 简略拍照,多媒体图片文件夹中选择图片
    来源: 互联网  发布时间: 2014-02-18
简单拍照,多媒体图片文件夹中选择图片
1.button.setOnClickListener(new OnClickListener(){      

           @Override

           public void onClick(View arg0) {        

              Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");      startActivityForResult(intent,SELECT_PICTURE_FROM_CAMERA);

           }

        });

//然后重载startActivityForResult添加自己的实现

@Override

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    if( resultCode==RESULT_OK)

    {

        if(requestCode==SELECT_PICTURE_FROM_CAMERA)

        {

            File image=new File(Environment.getExternalStorageDirectory(), "camera.jpg");

            selectedImagePath=image.getAbsolutePath();

            Drawable d=Drawable.createFromPath(selectedImagePath);

            ImageView.setImageDrawable(d);

        }

    }

}



2 从android本地多媒体图片文件夹中选择图片
Intent i=new Intent(Intent.ACTION_GET_CONTENT);

              i.setType("image/*");

              Intent wrapi=Intent.createChooser(i, "choose");

              startActivityForResult(wrapi, SELECT_PICTURE_FROM_FILE);

//然后重载startActivityForResult添加自己的实现

@Override

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    if( resultCode==RESULT_OK)

    {

        if(requestCode==SELECT_PICTURE_FROM_FILE )

        {

        Uri selectedImageUri = data.getData();

        selectedImagePath=getPath(selectedImageUri);

        imageView.setImageURI(selectedImageUri);

        }

    }

}   //获取当前选择的图片,并显示在imageView上

    private String getPath(Uri uri)

    {

    String[] projection={MediaStore.Images.Media.DATA};

    Cursor cursor=managedQuery(uri,projection,null,null,null);

    int column_index=cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);

    cursor.moveToFirst();

    return cursor.getString(column_index);

}  

//Query实现从图片数据库中查询到所要记录



3 Activity之间带内容的跳转
Intent intent = new Intent();

                  Bundle imageMsg = new Bundle();

                  imageMsg.putString("filePath", selectedImagePath); /               intent.putExtras(imageMsg);

                  intent.setClass(ActivityA.this,ActivityB.class);

                  startActivity(intent);

                  ActivityA.this.finish();



4 位图缩放
public Bitmap zoomImage(Bitmap bgimage, int newWidth, int newHeight) {  

       int width = bgimage.getWidth();

       int height = bgimage.getHeight();



       Matrix matrix = new Matrix();



       float scaleWidth = ((float) newWidth) / width;

       float scaleHeight = ((float) newHeight) / height;



       matrix.postScale(scaleWidth, scaleHeight);

       Bitmap bitmap = Bitmap.createBitmap(bgimage, 0, 0, width, height,

       matrix, true);

       return bitmap;



       }



5 Gallery的使用
Gallery gallery=(Gallery)findViewById(R.id.gallery);

        myImageAdapter imageadapter=new myImageAdapter(this); //传入context

        gallery.setAdapter(imageadapter);

        gallery.setOnItemClickListener(new Gallery.OnItemClickListener(){

           @Override

           public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {

              Bitmap selectedBitmap=BitmapFactory.decodeResource(getResources(),imageadapter.myImageIds[arg2]);

           }

        });

        gallery.setSelection(1);



//adapter的类定义

public class myImageAdapter extends BaseAdapter{



    int mGalleryItemBackground;

    private Context context;

    public Integer[] myImageIds={

           //图片的资源id号

    };

    public myImageAdapter(Context context)

    {

       this.context=context;

       TypedArray typed_array=context.obtainStyledAttributes(R.styleable.Gallery);

     

    mGalleryItemBackground=typed_array.getResourceId(R.styleable.Gallery_android_galleryItemBackground   , 0);

       //mGalleryItemBackground++;

       typed_array.recycle();

    }

    @Override

    public int getCount() {

       // TODO Auto-generated method stub

       return myImageIds.length;

    }



    @Override

    public Object getItem(int arg0) {

       // TODO Auto-generated method stub

       return arg0;

    }



    @Override

    public long getItemId(int arg0) {

       // TODO Auto-generated method stub

       return arg0;

    }



    @Override

    public View getView(int arg0, View arg1, ViewGroup arg2) {

       // TODO Auto-generated method stub

       ImageView imageView=new ImageView(context);

       imageView.setImageResource(myImageIds[arg0]);

     

       imageView.setScaleType(ImageView.ScaleType.FIT_XY);

       imageView.setLayoutParams(new Gallery.LayoutParams(128,128));

       imageView.setBackgroundResource(mGalleryItemBackground);

       return imageView;

    }



}



6 activity中使用线程
private Handler mHandler=new Handler();

private Runnable mRunnable=new Runnable()

    {

       @Override

       public void run() {

           // TODO Auto-generated method stub

       }

};

mHandler.post(mRunnable);              //启动线程


7 保存到android多媒体图片文件夹
android.provider.MediaStore.Images.Media.insertImage(getContentResolver(),resultBitmap, "picName", "descrition");

    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
oracle iis7站长之家
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3