android 内存走漏调试

二 、Android(Java)浙江中国广播公司大的简单滋生内存泄漏的蹩脚代码

    Android主要行使在嵌入式设备在那之中,而嵌入式设备由于局地明明的基准限制,平日都不会有很高的布局,尤其是内部存款和储蓄器是比较单薄的。要是大家编辑的代码个中有太多的对内部存款和储蓄器使用不当的地点,难免会使得大家的装备运行缓慢,甚至是死机。为了能够使得Android应用程序安全且快速的运作,Android的各样应用程序都会使用四个专有的Dalvik虚拟机实例来运维,它是由Zygote服务进度孵化出来的,也正是说每一种应用程序都是在属于本身的历程中运作的。一方面,要是程序在运维进程中出现了内部存储器泄漏的标题,仅仅会使得本人的进度被kill掉,而不会影响其余进度(假设是system_process等系统经过出难点来说,则会唤起系统重启)。另一方面Android为分歧档次的经过分配了分歧的内部存款和储蓄器使用上限,就算使用进度使用的内部存款和储蓄器当先了这么些上限,则会被系统便是内部存款和储蓄器泄漏,从而被kill掉。Android为运用进度分配的内部存款和储蓄器上限如下所示:

位置: /ANDROID_SOU汉兰达CE/system/core/rootdir/init.rc 部分脚本

# Define the oom_adj values for the classes of processes that can be

# killed by the kernel.  These are used in ActivityManagerService.

    setprop ro.FOREGROUND_APP_ADJ 0

    setprop ro.VISIBLE_APP_ADJ 1

    setprop ro.SECONDARY_SERVER_ADJ 2

    setprop ro.BACKUP_APP_ADJ 2

    setprop ro.HOME_APP_ADJ 4

    setprop ro.HIDDEN_APP_MIN_ADJ 7

    setprop ro.CONTENT_PROVIDER_ADJ 14

    setprop ro.EMPTY_APP_ADJ 15

 

# Define the memory thresholds at which the above process classes will

# be killed.  These numbers are in pages (4k).

    setprop ro.FOREGROUND_APP_MEM 1536

    setprop ro.VISIBLE_APP_MEM 2048

    setprop ro.SECONDARY_SERVER_MEM 4096

    setprop ro.BACKUP_APP_MEM 4096

    setprop ro.HOME_APP_MEM 4096

    setprop ro.HIDDEN_APP_MEM 5120

    setprop ro.CONTENT_PROVIDER_MEM 5632

    setprop ro.EMPTY_APP_MEM 6144

 

# Write value must be consistent with the above properties.

# Note that the driver only supports 6 slots, so we have HOME_APP at the

# same memory level as services.

    write /sys/module/lowmemorykiller/parameters/adj 0,1,2,7,14,15

 

    write /proc/sys/vm/overcommit_memory 1

    write /proc/sys/vm/min_free_order_shift 4

    write /sys/module/lowmemorykiller/parameters/minfree 1536,2048,4096,5120,5632,6144

 

    # Set init its forked children’s oom_adj.

    write /proc/1/oom_adj -16

 

    正因为我们的应用程序能够使用的内部存款和储蓄器有限,所以在编写代码的时候须求越发注意内部存款和储蓄器使用难题。如下是部分常见的内部存款和储蓄器使用不当的情况。

 

正文指标在于记录在FreeCAD源码阅读中询问到的一些东西。

一、概述

    Java编制程序中时常不难被忽视,但本身又特别主要的叁个难点正是内部存款和储蓄器使用的难点。Android应用首要使用Java语言编写,由此这些标题也一如既往会在Android开发中出现。本文不对Java编制程序难题做探索,而是对于在Android中,尤其是使用开发中的此类题材开始展览重新整建。

    由于笔者接触Android时间并不是十分长,因而如有叙述不当之处,欢迎指正。

FreeCAD编译

FreeCAD源码的编写翻译最棒应用官方提供的LibPack,不然第③方库难以找全,找到之后还须求协调编写翻译,此外还不清楚CMake是或不是能够那么百步穿杨找好(find_package)自个儿设的第二方库。采取官方提供的LibPack可以撤除这一大堆的麻烦。然而官方的LibPack仅有提供针对性VS2010,
VS2012,
VS2011x64的版本,分别能够在FreeCAD在github上的颁发地方0.16和0.15版本地方找到(VC9,
VC12),而sourceforge地址还足以找到x64的VS二零一二。

自小编动用的LibPack是FreeCADLibs_11.0_x64_VC11.7z本子,这些本子在boost_python上有lib和dll缺点和失误,能够从boost官方预编译版本1.55.0本子拷贝x六十人相应的lib和dll,也能够从FreeCADLibs_10.0_x64_VC11.7z里边把伍个公文拷贝出来。

源码接纳0.16的,没有行使0.17_pre,目的首要在于编写翻译出来看看,没有去追求官方最新的版本。解压source,LibPack默许是与源码放置同一目录的,假若要放置在差异的目录,能够将CMakeLists.txt第贰25行set(FREECAD_LIBPACK_DIR
${CMAKE_SOURCE_DIR} CACHE PATH “Directory of the FreeCAD
LibPack”)中的${CMAKE_SOURCE_DIR}改为${CMAKE_BINARY_DIHaval},cmake-gui.exe能够圆满通过。

一、概述 1

工程项指标简短分析

可以将FreeCAD_trunk.sln目录之下的体系分为两类,一类为
FreeCAD打头的根底工程项目;另一类为Mod模块工程。基础工程项目列表如下:

工程项目 产生文件 备注
FreeCADMain FreeCAD.exe FreeCAD主执行启动文件,main()函数所在地
FreeCADMainPy FreeCAD.pyd 兼容Python的扩展dll,导出initFreeCAD()
FreeCADMainCmd FreeCADCmd.exe App::Application::Config()["RunMode"]有三种模式,Gui、Exit、Console,这里对应的是Exit模式,执行(argc, argv)之后自动退出
FreeCADGui FreeCADGui.dll 命名空间Gui,Command,Workbench,View3dInventor(视图),Gui层的Document
FreeCADGuiPy FreeCADGui.pyd 兼容Python的扩展dll
FreeCADBase FreeCADBase.dll 代码基础与上层,命名空间Base,Type类型体系,InterpreterSingleton脚本解释器
FreeCADApp FreeCADApp.dll 表征exe执行所在的应用,命名空间App,App::GetApplication()可以获取唯一的那个pcSingleton指针,App层Document

上述这一个就建构了FreeCAD运营的根底框架,它们其实仅使用了Python, Boost,
PySide, shiboken, xerces-c, zlib,
coin3d等那几个,别的的Mod都是模块增添,正视诸如OCE,PCL,Eigen3,libqhull等等,每一种Mod工程项目分为带Gui的及不带Gui的本子。带Gui的项目概念了可用的Command,Workbench(工作台),突显等那么些。

就此FreeCAD对Python注重如此之深,是因为本质上FreeCAD全部的下令达成都以经过Python语句来兑现的。比如一个Box的创办命令是那般的:

C++
void CmdPartBox::activated(int iMsg)
{
    QString cmd;
    cmd = qApp->translate("CmdPartBox","Cube");
    openCommand((const char*)cmd.toUtf8());

    doCommand(Doc,"App.ActiveDocument.addObject(\"Part::Box\",\"Box\")");
    cmd = QString::fromLatin1("App.ActiveDocument.ActiveObject.Label = \"%1\"")
        .arg(qApp->translate("CmdPartBox","Cube"));
    doCommand(Doc,(const char*)cmd.toUtf8());
    commitCommand();
    updateActive();
    doCommand(Gui, "Gui.SendMsgToActiveView(\"ViewFit\")");
}

个中那个都以发送给解释器的Python语句呀,执行后会在界面上的Python
Console窗口播报Python执行语句,那样摄像宏就简单极了,别的也得以全方位施用Python来建立模型恐怕写个成效完毕,比如就有个SheetMetal就全盘是用Python来贯彻。

Command命令的靶子是发出NewObject参与Document,特征附有属性,然后recompute()执行计算,那样就能够重生成,响应修改属性的结果。

 

其三方库粗略记录

没列举齐全的第1方库表格如下:

Lib Name version in LibPack_11.0_x64_VC11 Link to get it
Python Python 2.7.8 http://www.python.org/
PySide 1.2.2 http://wiki.qt.io/PySide
shiboken 1.2.2 http://shiboken.readthedocs.io/en/latest/
Qt Qt 4 https://www.qt.io/
Boost 1.55.0 http://www.boost.org/
Coin3D 4.0 https://bitbucket.org/Coin3D/coin/wiki/Home
SoQt 1.2 https://bitbucket.org/Coin3D/soqt
OpenCASCADE oce-16(对应6.7.1) http://www.opencascade.com

在上述第二方库中,PySide是Python与Qt的融合,能够采用Python语言营造Gui。建议是在Python2.7密密麻麻中使用,协理部分Python3,与PySide有雷同效果的PyQt相对成熟一些,但商用供给付费,推测那是FreeCAD接纳PySide的因由,PySide是Qt官方出的,完毕了对Qt4.8本子的欧洲经济共同体兑现,协助Qt5的PySide2也足以在github中找到。shiboken作何用途,我还没弄得很了解。

FreeCAD对Python是重度信赖,不可能不够。若是协调来搞第二方库,就必须先消除Python,PySide,Boost,shiboken,所以使用官方提供的LibPack是能够节约比比皆是劳动的。

(二) 构造Adapter时,没有行使缓存的 convertView

描述:

    以协会ListView的BaseAdapter为例,在Base艾达pter中增进了主意:

public View getView(int position, View convertView, ViewGroup parent)

来向ListView提供每1个item所急需的view对象。初叶时ListView会从BaseAdapter中依据当前的荧屏布局实例化一定数额的view对象,同时ListView会将这一个view对象缓存起来。当发展滚动ListView时,原先位于最下面的list item的view对象会被回收,然后被用来组织新出现的最上边包车型大巴list item。这几个结构进度便是由getView()方法成功的,getView()的第①个形参 View convertView正是被缓存起来的list item的view对象(伊始化时缓存中一向不view对象则convertView是null)。

    因此可以看看,若是大家不去行使convertView,而是每趟都在getView()中重复实例化四个View对象的话,即浪费能源也浪费时间,也会使得内存占用越来越大。ListView回收list item的view对象的进度能够查看:

android.widget.AbsListView.java –> void addScrapView(View scrap) 方法。

 

演示代码:

public View getView(int position, View convertView, ViewGroup parent) {

    View view = new Xxx(…);

    … …

    return view;

}

 

校勘示例代码:

public View getView(int position, View convertView, ViewGroup parent) {

    View view = null;

    if (convertView != null) {

        view = convertView;

        populate(view, getItem(position));

        …

    } else {

        view = new Xxx(…);

        …

    }

    return view;

 

小结

2017/12/22
FreeCAD架构类别依然很显著的,也兑现了众多要义(比如Undo/Redo,参数化,自动保存等),模块也包揽很多;Python嵌入好坏不佳评价,但自笔者个人非常小习惯。总的来说给作者的感觉到是不精致。

(三) 使用MAT的视图工具分析内部存款和储蓄器 8

关于BUILD_JTREADER

因为作者对JT格式做过分析,发现FreeCAD里边有这几个选项,就专门在意了瞬间。须要提示的是BUILD_JTREADEEvoque在那一个版本无效,因为src/Mod上面没有JtReader文件夹,0.17_pre里边也远非,可是github最新版的源码里有该公文夹。略略地看了一晃,达成不会细小略,跳过不少事物,相比较OpenCASCADE官方提供的TKJT弱很多(不过OCC的TKJT也很久没更新了,一更新就到了亟待付费能够获得里边去了)。可是FreeCAD还有个JTREADE奇骏.h文件,调用了JtOpen的头文件呀,那些牛,可惜JtOpen试用版一般唯有三个月啊。

(一) 查询数据库没有停歇游标

描述:

    程序中时时会开始展览查询数据库的操作,不过平日会有接纳完结Cursor后并未关闭的景况。要是大家的询问结果集相比小,对内部存款和储蓄器的损耗不便于被发现,唯有在常时间大批量操作的情形下才会复现内存难点,那样就会给今后的测试和题材排查带来不便和高风险。

 

演示代码:

Cursor cursor = getContentResolver().query(uri …);

if (cursor.moveToNext()) {

    … … 

}

 

改良示例代码:

Cursor cursor = null;

try {

    cursor = getContentResolver().query(uri …);

    if (cursor != null && cursor.moveToNext()) {

        … … 

    }

} finally {

    if (cursor != null) {

        try { 

            cursor.close();

        } catch (Exception e) {

            //ignore this

        }

    }

 

fcstd文件格式分析

fcstd是FreeCAD存储下来的文书,这么些格式实际上正是zip压缩文件,能够修改后缀成为zip只怕直接拖拽至刚打开的WinRA揽胜能够观看里面包车型大巴文件,容易的话就陆个,多的话数量不少。在那之中Document.xml是对应FreeCADApp里边的Doc,GuiDocument.xml对应FreeCADGui里边的Doc,别的有PartShape.brp文件正是OpenCASCADE官方的brep格式呀。

(五) 其他 5

Sketcher草图

为此说草图,是发现FreeCAD的草图看起来还不易,实时可知(差别于实体的创设),能够捕捉到线段的端点,中式点心,两条线的交点等这个。

  • CmdSketcherCreateLine
    是草图绘制线段的指令,该命令在激活时会调用ActivateHandler(getActiveGuiDocument(),
    new
    DrawSketchHandlerLine())将这些handler交给SketcherGui::ViewProviderSketch激活
  • DrawSketchHandlerLine 派生自
    DrawSketchHandler,会有个mouseMove()的函数重载定义鼠标行为,并调用seekAutoConstraint(),
    renderSuggestConstraitsCursor()
  • App里边有个planegcs文件夹,里边可以对约束求解,代码稍微有个别多没细看,相比较D-Cubed怎样就不明白了

(三) Bitmap对象不在使用时调用recycle()释放内部存款和储蓄器

描述:

    有时大家会手工业的操作Bitmap对象,假如一个Bitmap对象比较占内部存款和储蓄器,当它不在被运用的时候,能够调用Bitmap.recycle()方法回收此指标的像素所占有的内部存款和储蓄器,但那不是必须的,视景况而定。能够看一下代码中的注释:

    /**

     * Free up the memory associated with this bitmap’s pixels, and mark the

     * bitmap as “dead”, meaning it will throw an exception if getPixels() or

     * setPixels() is called, and will draw nothing. This operation cannot be

     * reversed, so it should only be called if you are sure there are no

     * further uses for the bitmap. This is an advanced call, and normally need

     * not be called, since the normal GC process will free up this memory when

     * there are no more references to this bitmap.

     */

(三) Bitmap对象不在使用时调用recycle()释放内部存款和储蓄器 4

(二) 使用MAT导入.hprof文件 8

二 、Android(Java)山东中国广播公司大的简单引起内部存款和储蓄器泄漏的倒霉代码 1

肆 、内部存款和储蓄器分析工具 MAT(Memory Analyzer Tool) 7

(一) 查询数据库没有停歇游标 2

 

(四) 释放对象的引用

描述:

    这种情景描述起来相比较费心,举多个例证实行表明。

示例A:

纵然有如下操作

public class DemoActivity extends Activity {

    … …

    private Handler mHandler = …

    private Object obj;

语言,    public void operation() {

     obj = initObj();

     …

     [Mark]

     mHandler.post(new Runnable() {

            public void run() {

             useObj(obj);

            }

     });

    }

}

    大家有1个成员变量 obj,在operation()中大家旨在能够将拍卖obj实例的操作post到有个别线程的MessageQueue中。在上述的代码中,即便是mHandler所在的线程使用完了obj所引用的靶子,但以此指标依旧不会被垃圾回收掉,因为德姆oActivity.obj还怀有那么些指标的引用。所以只要在德姆oActivity中不再采纳这一个指标了,能够在[Mark]的职位释放对象的引用,而代码能够修改为:

… …

public void operation() {

    obj = initObj();

    …

    final Object o = obj;

    obj = null;

    mHandler.post(new Runnable() {

        public void run() {

            useObj(o);

        }

    }

}

… …

 

示例B:

    若是我们愿意在锁屏界面(LockScreen)中,监听系统中的电话服务以赢得一些新闻(如信号强度等),则能够在LockScreen中定义2个PhoneStateListener的指标,同时将它注册到TelephonyManager服务中。对于LockScreen对象,当必要出示锁屏界面包车型大巴时候就会创立一个LockScreen对象,而当锁屏界面消失的时候LockScreen对象就会被放飞掉。

    不过只要在刑释LockScreen对象的时候忘记裁撤我们事先注册的PhoneStateListener对象,则会招致LockScreen无法被垃圾回收。借使持续的使锁屏界面展现和消逝,则最后会由于大气的LockScreen对象没有艺术被回收而引起OutOfMemory,使得system_process进度挂掉。

    总之当三个生命周期较短的指标A,被一个生命周期较长的目的B保有其引述的景况下,在A的生命周期结束时,要在B中消除掉对A的引用。

(四) 释放对象的引用 4

(二) 构造Adapter时,没有动用缓存的 convertView 3

三 、内部存储器监测工具 DDMS –> Heap 5

(五) 其他

    Android应用程序中最非凡的内需小心释放能源的情景是在Activity的生命周期中,在onPause()、onStop()、onDestroy()方法中须要适量的假释财富的气象。由于此情状很基础,在此不详细表达,具体能够查看官方文档对Activity生命周期的介绍,以明显几时应该释放怎样能源。

http://rayleeya.iteye.com/blog/727074

(一) 生成.hprof文件 7

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图