写了可执行文件启动器Launcher.jar及一些批处理,通过它们就可以自动的以一定的时间间隔提取Hprof和进程的内存信息;

一、需要的库

可执行文件启动器:lib\Launcher.jar

:关于Launcher.jar的源码如下:

源码包含2个文件Worker.java和Launcher.java

Worker.java文件:

package com.teleca.robin;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 
import javax.swing.JLabel;
import javax.swing.JTextField;
 
public class Worker extends Thread {
    private boolean loop=true;
    private boolean paused=false;
    private int cnt=0;
    final private JLabel consoleText;
    Worker(JLabel lable)
    {
    consoleText=lable;
    }
    private long interval=1000;
    void setInterval(long interval)
    {
    this.interval=interval;
    }
    private String executableFileName;
    void setExecutableFileName(String file)
    {
    if(executableFileName!=null&&file!=null)
    {
    if(!executableFileName.equals(file))
    cnt=0;
    }
    executableFileName=file;
    }
   public void doPause()
    {
    paused=true;
    }
    public void doResume()
    {
    paused=false;
    interrupt();
    }
    public void die()
    {
    loop=false;
    }
    public void run()
    {
    while(loop)
    {
    if(paused||executableFileName==null)
    {
    try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
}
    }
    else
    {
     BufferedReader stdout = null;
     try {
    Process p = null;
    String line = null;
    p = Runtime.getRuntime().exec(executableFileName, null, null);
    stdout = new BufferedReader(new InputStreamReader(p
      .getInputStream()));
    while ((line = stdout.readLine()) != null) {
     System.out.println(line);
    }
    stdout.close();
    stdout=null;
   } catch (IOException e) {
    e.printStackTrace();
   }finally{
   if(stdout!=null)
try {
stdout.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
   }
    cnt++;
    if(consoleText!=null)
    consoleText.setText("Execute the file "+cnt+" times");
    try {
Thread.sleep(interval);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
}
    }
    }
    System.out.println("exit!");
    }
}

源码文件2:Launcher.java

package com.teleca.robin;

import java.awt.event.WindowEvent;

import java.awt.event.WindowListener;

import java.io.BufferedReader;

import java.io.File;

import java.io.IOException;

import java.io.InputStreamReader;

import javax.swing.JFrame;

import javax.swing.JTextField;

import javax.swing.SwingConstants;

public class Launcher extends JFrame implements WindowListener{

private long interval;

private String executableFileName;

Launcher(String file,long time)

{

if(file==null)

executableFileName="";

else

executableFileName=file;

interval=time;

initComponents();

this.addWindowListener(this);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

}

/** This method is called from within the constructor to

* initialize the form.

* WARNING: Do NOT modify this code. The content of this method is

* always regenerated by the Form Editor.

*/

// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents

private void initComponents() {

jButtonStart = new javax.swing.JButton();

jButtonPause = new javax.swing.JButton();

jButtonExit = new javax.swing.JButton();

jTextFieldFile = new javax.swing.JTextField(20);

jTextFieldTime = new javax.swing.JTextField(5);

jLabelFile = new javax.swing.JLabel();

jLabelTime = new javax.swing.JLabel();

jLabelTip = new javax.swing.JLabel();

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

setName("Form"); // NOI18N

jButtonStart.setText("Start"); // NOI18N

jButtonStart.setName("jButtonStart"); // NOI18N

jButtonStart.addActionListener(new java.awt.event.ActionListener() {

public void actionPerformed(java.awt.event.ActionEvent evt) {

start();

}

});

jButtonPause.setText("Pause"); // NOI18N

jButtonPause.setName("jButtonPause"); // NOI18N

jButtonPause.addActionListener(new java.awt.event.ActionListener() {

public void actionPerformed(java.awt.event.ActionEvent evt) {

pause();

}

});

jButtonExit.setText("Exit"); // NOI18N

jButtonExit.setName("jButtonExit"); // NOI18N

jButtonExit.addActionListener(new java.awt.event.ActionListener() {

public void actionPerformed(java.awt.event.ActionEvent evt) {

stop();

System.exit(0);

}

});

jButtonStart.setEnabled(true);

jButtonPause.setEnabled(false);

jTextFieldFile.setText(executableFileName); // NOI18N

jTextFieldFile.setName("jTextFieldFile"); // NOI18N

jTextFieldFile.setHorizontalAlignment(JTextField.CENTER);

jTextFieldTime.setText(""+interval); // NOI18N

jTextFieldTime.setName("jTextFieldTime"); // NOI18N

jTextFieldTime.setHorizontalAlignment(JTextField.CENTER);

jLabelFile.setText("the executable file"); // NOI18N

jLabelFile.setName("jLabelFile"); // NOI18N

jLabelTime.setText("the interval time(millisecond)"); // NOI18N

jLabelTime.setName("jLabelTime"); // NOI18N

jLabelTip.setText("idle"); // NOI18N

jLabelTip.setName("jLabelTip"); // NOI18N

jLabelTip.setHorizontalAlignment(SwingConstants.CENTER);

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());

getContentPane().setLayout(layout);

layout.setHorizontalGroup(

layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)

.addGroup(layout.createSequentialGroup()

.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)

.addGroup(layout.createSequentialGroup()

.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)

.addGroup(layout.createSequentialGroup()

.addGap(71, 71, 71)

.addComponent(jLabelTime))

.addGroup(layout.createSequentialGroup()

.addGap(70, 70, 70)

.addComponent(jLabelFile))

.addGroup(layout.createSequentialGroup()

.addGap(90, 90, 90)

.addComponent(jButtonStart)))

.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)

.addGroup(layout.createSequentialGroup()

.addGap(100, 100, 100)

.addComponent(jTextFieldTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))

.addGroup(layout.createSequentialGroup()

.addComponent(jTextFieldFile, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)

)

.addGroup(layout.createSequentialGroup()

.addGap(10, 10, 10)

.addComponent(jButtonPause)

)

.addGroup(layout.createSequentialGroup()

.addGap(20, 20, 20)

.addComponent(jLabelTip)

)

.addGroup(layout.createSequentialGroup()

.addGap(180, 180, 180)

.addComponent(jButtonExit)

)

))

)

.addContainerGap(151, Short.MAX_VALUE))

);

layout.setVerticalGroup(

layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)

.addGroup(layout.createSequentialGroup()

.addGap(63, 63, 63)

.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)

.addComponent(jLabelFile)

.addComponent(jTextFieldFile, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))

.addGap(29, 29, 29)

.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)

.addComponent(jLabelTime)

.addComponent(jTextFieldTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))

.addGap(62, 62, 62)

.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)

.addComponent(jButtonStart)

.addComponent(jButtonPause)

.addComponent(jButtonExit))

.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 34, Short.MAX_VALUE)

.addComponent(jLabelTip)

.addGap(32, 32, 32))

);

pack();

}// </editor-fold>//GEN-END:initComponents

Worker worker;

private void stop() {//GEN-FIRST:event_stop

// TODO add your handling code here:

if(worker!=null)

{

worker.die();

worker=null;

}

}//GEN-LAST:event_stop

private void pause() {//GEN-FIRST:event_pause

// TODO add your handling code here:

worker.doPause();

jButtonStart.setEnabled(true);

jButtonPause.setEnabled(false);

jTextFieldFile.setEditable(true);

jTextFieldTime.setEditable(true);

}//GEN-LAST:event_pause

private void start() {//GEN-FIRST:event_start

// TODO add your handling code here:

String fileName=jTextFieldFile.getText().trim();

if(checkFileName(fileName))

{

executableFileName=fileName;

}

else

{

return;

}

String time=jTextFieldTime.getText();

if(time.length()==0)

{

interval=defaultInterval;

}

else

{

try{

long t=Long.parseLong(time);

interval=t;

}catch(NumberFormatException e)

{

jLabelTip.setText("the time "+time+"is not correct!");

return;

}

}

if(worker==null)

{

worker=new Worker(this.jLabelTip);

worker.setExecutableFileName(executableFileName);

worker.setInterval(interval);

worker.start();

jLabelTip.setText("start to execute file");

}

else

{

worker.setExecutableFileName(executableFileName);

worker.setInterval(interval);

worker.doResume();

jLabelTip.setText("Restart to execute file");

}

jButtonStart.setEnabled(false);

jButtonPause.setEnabled(true);

jTextFieldFile.setEditable(false);

jTextFieldTime.setEditable(false);

}//GEN-LAST:event_start

final static  long defaultInterval=1000;

/**

* @param args

*/

public static void main(String[] args) {

String fileName="";

long time=defaultInterval;

if(args.length>0)

{

fileName=args[0];

if(!checkFileName(fileName))

{

fileName="";

}

}

if(args.length>1)

{

time=Long.parseLong(args[1]);

}

// TODO Auto-generated method stub

new Launcher(fileName,time).setVisible(true);

}

static boolean checkFileName(String fileName)

{

if(fileName==null)

{

return false;

}

if(!(fileName.endsWith(".exe")||fileName.endsWith(".bat")||fileName.endsWith(".cmd")))

{

System.out.println("the file must be a executable file!");

System.out.println("Now only support *.exe , *.bat,*.cmd");

System.out.println("Please check the file again");

return false;

}

File file=new File(fileName);

if(!file.exists())

{

System.out.println("the file:"+fileName+" is not exists");

return false;

}

return true;

}

// Variables declaration - do not modify//GEN-BEGIN:variables

private javax.swing.JButton jButtonExit;

private javax.swing.JButton jButtonPause;

private javax.swing.JButton jButtonStart;

private javax.swing.JLabel jLabelFile;

private javax.swing.JLabel jLabelTime;

private javax.swing.JLabel jLabelTip;

private javax.swing.JTextField jTextFieldFile;

private javax.swing.JTextField jTextFieldTime;

// End of variables declaration//GEN-END:variables

public void windowDeactivated(WindowEvent e)

{

//System.out.println("window is deactivated");

}

public void windowDeiconified(WindowEvent e)

{

//System.out.println("window is Deiconified");

}

public void windowActivated(WindowEvent e)

{

//System.out.println("window is actived");

}

public void windowOpened(WindowEvent e)

{

//System.out.println("window is Opened");

}

public void windowClosing(WindowEvent e)

{

stop();

}

public void windowClosed(WindowEvent e)

{

//System.out.println("window is Closed");

}

public void windowIconified(WindowEvent e)

{

//System.out.println("window is Closing");

}

}

用源代码生成的jar文件为:Launcher.jar。

则可以用如下的DOS命令运行它:

java -jar lib\Launcher.jar getProcessState.bat 5000
表示每隔5000毫秒执行一次getProcessState.bat 文件。
 
二、自动提取Hprof。
runHprofPicker.bat文件:
表示5000毫秒执行一次 getHprof.bat来从手机提取Hprof文件。
 
getHprof.bat文件如下:
@echo off
call config.bat
if exist %hpInputFile% (
del %hpInputFile% /q
)
adb pull %hpInputFileDir%/%hpInputFile% .
if not exist %hpInputFile% (
echo fail to pull %hpInputFile%
exit 1
)
if not exist %hpRoot% (
md %hpRoot%
)
Setlocal enabledelayedexpansion
set path=%path%;%cd%\lib
call genSerial
set serial=!genSerial~result!
set hpOutFile=%serial%.hprof
%tools%\hprof-conv.exe %hpInputFile% %hpRoot%\%hpOutFile%
echo success!
endlocal
 
前提:
1生成批处理配置文件config.bat:
批处理配置文件config.bat如下:
rem the following var is for getProcessState.bat
set rawDatadir=rawData
set processName=android.process.acore;com.android.systemui
rem set processShortName=a;b;c
set processShortName=
set outRoot=out
set statFilePrefix=stat
rem the following var is for getHprof.bat
set tools=D:\SDK\android-sdk4.0\tools
set hpInputFileDir=/sdcard
set hpInputFile=input.hprof
set hpRoot=hpTemp
注1:rawDatadir为“ps -x”提取出来的文件的目录
注2:processName需要统计RSS的进程的名字,可以同时统计多个,进程名之间用“;”进行分割。
注3:processShortName需要统计RSS的进程的名字的缩写形式,如果不坐设置或设置为空,这程序会根据processName自动生成。
注4:outRoot为对进程的RSS进行统计最后的生成文件的存放目录。
注5:statFilePrefix为对进程的RSS进行统计最后的生成文件的前缀。
注6:tools为hprof-conv.exe所在的目录。
注7:hpInputFileDir为手机中我们生成的hprof文件所在的目录。
注8:hpInputFileDir为手机中我们生成的hprof文件的名字。
2.在代码中生成Hprof文件
在android代码,可以使用如下代码把hprof文件生成到sd卡上。
Debug.dumpHprofData("/sdcard/input.hprof");
可以不用sd卡,而将hprof文件直接生成在手机上,但是只能在"/data/data/"+packageName的目录下。
实例1
    void generateHprof()
    {
String packageName=getApplicationInfo().packageName;
String hpFilePath="/data/data/"+packageName+"/input.hprof";
try {
//Debug.dumpHprofData("/sdcard/input.hprof");
Debug.dumpHprofData(hpFilePath);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
    }
注1:需要在代码中先生成hprof文件,而且config.bat中配置的路径要和在代码中先生成hprof文件的路径一致。

2:需要把bat库genSerial.bat,getSubStr.bat放在子目录lib中。(如下实例)
 
getSubStr.bat源码

@echo off
set %0~string=%string%
set %0~position=%position%
set %0~count=%count%
set %0~result=
set string=%1
set /a position=%2
set /a count=0
set string=%string:"=%
if %position% LSS 0 (
for %%i in (%string%) do (
set /a count=!count!+1
)
set /a position=%position%+!count!
)
set /a count=0
for %%i in (%string%) do (
if !count! EQU %position% (
set %0~result=%%i
set /a count=!count!+1
)
set string=!%0~string!
set position=!%0~position!
set count=!%0~count!

使用实例1:

@echo off
Setlocal enabledelayedexpansion
set path=%path%;%cd%\lib
call getSubStr "a,b,c,d" 0
set result=!getSubStr~result!
echo the first subString is %result%
call getSubStr "a;b;c;d" 1
set result=!getSubStr~result!
echo the second subString is %result%
call getSubStr "a b c d" -1
set result=!getSubStr~result!
echo the firest subString from right is %result%
pause
 
genSerial.bat文件

@echo off
set %0~SNFile=%SNFile%
set %0~SN=%SN%
set %0~result=
set SNFile=SN.txt
if "%1" =="reset" (
set /a SN=0
goto save
)
if exist %SNFile% (
for /f %%i in (%SNFile%) do set /a SN=%%i
set /a SN+=1
) else (
set /a SN=0
)
:save
echo %SN% >%SNFile%
set %0~result=%SN%
set SNFile=!%0~SNFile!
set SN=!%0~SN!
使用实例1
@echo off
Setlocal enabledelayedexpansion
set path=%path%;%cd%\lib
call genSerial
set serial=%genSerial~result%
echo the serial is %serial%
call genSerial
set serial=!genSerial~result!
echo the serial is %serial%
call genSerial reset
set serial=!genSerial~result!
echo after reset,the serial is %serial%
pause
 
三、自动提取进程的RSS
runProcessStatePicker.bat文件:
java -jar lib\Launcher.jar getProcessState.bat 5000
表示5000毫秒执行一次 getProcessState.bat来从手机提取进程的RSS,输出到一个以进程名命名的文本文件,以便在excel中生产图表文件。
前言:RSS(Resident Set Size)表示实际使用物理内存(包含共享库占用的内存)。
因为它包含了共享内存,所以他的意义不及PSS。所以现在查看内存使用情况一般参照PSS。
提取进程的RSS
文件:getProcessState.bat
@echo off
call config.bat
set processNameCol=9
set RSSCol=5
Setlocal enabledelayedexpansion
set path=%path%;%cd%\lib
set /a processNo=0
for %%i in (%processName%) do (
set /a processNo+=1
)
set /a cnt=0
set str=
if "%processShortName%"=="" (
set /a cnt=0
for %%i in (%processName%) do (
set str=%%i
set str=!str:.= !
call getSubStr "!str!" -1
set result=!getSubStr~result!
if !cnt! EQU 0 (
set processShortName=!result!
) else (
set processShortName=!processShortName!;!result!
)
set /a cnt+=1
)
) else (
set /a cnt=0
for %%i in (%processShortName%) do (
set /a cnt=!cnt!+1
)
if not !cnt! EQU %processNo% (
echo the number of process Name is %processNo%
echo the number of process Short Name is !cnt!
echo they should be equal.Please check again!
exit 0
)
)
if not exist %rawDatadir% (
md %rawDatadir%
)
if not exist %outRoot% (
md %outRoot%
)
call genSerial
set serial=!genSerial~result!
set psFile=%rawDatadir%\ps%serial%.txt
adb shell "ps -x" >%psFile%
adb shell exit
set /a cnt=0
FOR /F "skip=1 tokens=%RSSCol%,%processNameCol%" %%i in (%psFile%) do (
set /a cnt=0
for %%a in (%processName%) do (
if "%%a"=="%%j" (
call getSubStr "%processShortName%" !cnt!
set result=!getSubStr~result!
set statFile=%outRoot%\%statFilePrefix%_!result!.txt
if exist !statFile! (
>>!statFile! set/p=,%%i<nul
) else (
>>!statFile! set/p=%%i<nul
)
)
set /a cnt=!cnt!+1
)
)
echo success!
endlocal
 
四、自动提取进程的NativeSize,DalvikSize,NativeAllocated,DalvikAllocated,NativePSS,DalvikPSS
runMemoryPicker.bat文件:
java -jar lib\Launcher.jar getMemoryState.bat 2000

表示2000毫秒执行一次 getMemoryState.bat来从手机提取进程的内存信息到一个以进程名命名的文本文件,以便在excel中生产图表文件。

前言:我们可以通过adb shell "dumpsys meminfo %curProcessName%"命令得到某个进程的内存使用情况。

getMemoryState.bat主要用于解析该命令返回的内存,得到NativeSize,DalvikSize,NativeAllocated,DalvikAllocated,NativePSS,DalvikPSS等。它把不同时期得到的数据按时间前后为顺序以逗号作为分隔符的排列输出到一个以进程名命名的文本文件,以便在excel中生产图表。
getMemoryState.bat文件源码
@echo off
call config.bat
set typeNameCol=1
set nativeValueCol=2
set dalvikValueCol=3
set dalvikOtherCol=4
Setlocal enabledelayedexpansion
set path=%path%;%cd%\lib
set /a processNo=0
for %%i in (%processName%) do (
set /a processNo+=1
)
set /a cnt=0
set str=
if "%processShortName%"=="" (
set /a cnt=0
for %%i in (%processName%) do (
set str=%%i
set str=!str:.= !
call getSubStr "!str!" -1
set result=!getSubStr~result!
if !cnt! EQU 0 (
set processShortName=!result!
) else (
set processShortName=!processShortName!;!result!
)
set /a cnt+=1
)
) else (
set /a cnt=0
for %%i in (%processShortName%) do (
set /a cnt=!cnt!+1
)
if not !cnt! EQU %processNo% (
echo the number of process Name is %processNo%
echo the number of process Short Name is !cnt!
echo they should be equal.Please check again!
exit 0
)
)
if not exist %rawDatadir% (
md %rawDatadir%
)
if not exist %outRoot% (
md %outRoot%
)
call genSerial
set serial=!genSerial~result!
set meminfoFile=%rawDatadir%\meminfo%serial%.txt
set slipChar=,
:Loop0Start:
set /a processTotalNumber=cnt
set /a processNo=0
:Loop0Head
call getSubStr "%processShortName%" %processNo%
set curProcessShortName=%getSubStr~result%
call getSubStr "%processName%" %processNo%
set curProcessName=%getSubStr~result%
:GetRawMemInfoFile
set statFile=%outRoot%\%statFilePrefix%_Memory_%curProcessShortName%.txt
adb shell "dumpsys meminfo %curProcessName%" >%meminfoFile%
if not exist %statFile% (
set slipChar=
goto ReadRawMemInfoFile
)
:ReadMemInfoStatisticFile
set NativeSize=
set DalvikSize=
set OtherSize=
set TotalSize=
set NativeAllocated=
set DalvikAllocated=
set OtherAllocated=
set TotalAllocated=
set NativePSS=
set DalvikPSS=
set OtherPSS=
set TotalPSS=
set NativeFree=
set DalvikFree=
set OtherFree=
set TotalFree=
set /a cnt=0
FOR /F "delims=: tokens=2" %%i in (%statFile%) do (
if !cnt! EQU 0 (
set NativeSize=%%i
)
if !cnt! EQU 1 (
set DalvikSize=%%i
if !cnt! EQU 2 (
set NativeAllocated=%%i
if !cnt! EQU 3 (
set DalvikAllocated=%%i
if !cnt! EQU 4 (
set NativePSS=%%i
if !cnt! EQU 5 (
set DalvikPSS=%%i
 
set /a cnt+=1
)
:ReadRawMemInfoFile
set /a cnt=0
FOR /F "skip=1 tokens=1,2,3,4,5,6,7,8" %%i in (%meminfoFile%) do (
if !cnt! EQU 4 (
set NativeSize=!NativeSize!%slipChar%%%j
set DalvikSize=!DalvikSize!%slipChar%%%k
set OtherSize=!OtherSize!%slipChar%%%l
set TotalSize=!TotalSize!%slipChar%%%m
if !cnt! EQU 5 (
set NativeAllocated=!NativeAllocated!%slipChar%%%j
set DalvikAllocated=!DalvikAllocated!%slipChar%%%k
set OtherAllocated=!OtherAllocated!%slipChar%%%l
set TotalAllocated=!TotalAllocated!%slipChar%%%m
)
if !cnt! EQU 6 (
set NativeFree=!NativeFree!%slipChar%%%j
set DalvikFree=!DalvikFree!%slipChar%%%k
set OtherFree=!OtherFree!%slipChar%%%l
set TotalFree=!TotalFree!%slipChar%%%m
)
if !cnt! EQU 7 (
set NativePSS=!NativePSS!%slipChar%%%k
set DalvikPSS=!DalvikPSS!%slipChar%%%l
set OtherPSS=!OtherPSS!%slipChar%%%m
set TotalPSS=!TotalPSS!%slipChar%%%n
)
set /a cnt+=1
 
)
:SaveToMemInfoStatisticFile
echo NativeSize:%NativeSize%>%statFile%
echo DalvikSize:%DalvikSize%>>%statFile%
echo NativeAllocated:%NativeAllocated%>>%statFile%
echo DalvikAllocated:%DalvikAllocated%>>%statFile%
echo NativePSS:%NativePSS%>>%statFile%
echo DalvikPSS:%DalvikPSS%>>%statFile%
:Loop0Tail
set /a processNo+=1
if %processNo% LSS %processTotalNumber% (
goto Loop0Head
)
:Loop0End
echo success!
endlocal
 
 

本文来自:http://hubingforever.blog.163.com/blog/static/1710405792011324114317115/

Android内存泄露(全自动篇)的更多相关文章

  1. (转)专项:Android 内存泄露实践分析

    今天看到一篇关于Android 内存泄露实践分析的文章,感觉不错,讲的还算详细,mark到这里. 原文发表于:Testerhome: 作者:ycwdaaaa ;  原文链接:https://teste ...

  2. Android内存泄露---检测工具篇

    内存使用是程序开发无法回避的一个问题.如果我们毫不在意肆意使用,总有一天会为此还账,且痛不欲生...所以应当防患于未然,把内存使用细化到平时的每一行代码中. 内存使用概念较大,本篇先讲对已有app如何 ...

  3. 【android内存泄露】 WebView篇

    在咱的博客园app里,新闻的内容使用WebView展示的.在测试中,咱重复进入.退出某个新闻10多次,观察到 Objects一直在不断增长,反复触发GC,但是一直回收不了,占用的内存越来越高,于是警觉 ...

  4. JVM内存管理概述与android内存泄露分析

    一.内存划分 将内存划分为六大部分,分别是PC寄存器.JAVA虚拟机栈.JAVA堆.方法区.运行时常量池以及本地方法栈. 1.PC寄存器(线程独有):全称是程序计数寄存器,它记载着每一个线程当前运行的 ...

  5. Android 内存泄露总结(附内存检测工具)

    https://segmentfault.com/a/1190000006852540 主要是分三块: 静态储存区:编译时就分配好,在程序整个运行期间都存在.它主要存放静态数据和常量. 栈区:当方法执 ...

  6. Android内存泄露

    Android 内存泄漏是一个十分头疼的事情.LeakCanary是一款开源软件,主要作用是检测 Android APP 内存泄露.比起以前的 MAT 工具,LeakCanary 有着十分强大的功能, ...

  7. android内存泄露调试,Heap,MAT

    三.内存监测工具 DDMS --> Heap 无论怎么小心,想完全避免bad code是不可能的,此时就需要一些工具来帮助我们检查代码中是否存在会造成内存泄漏的地方.Android tools中 ...

  8. Android内存泄露测试

    Android性能测试过程中的一些常用命令: CPU: adb shell top -n | grep "+PackageName 内存: adb shell dumpsys meminfo ...

  9. android内存泄露小谈

    在做android的时候,用的语言大部分情况下都是java.以前最开始做的是编译器开发, 大部分情况都是用c语言和x86与arm架构的汇编,后来接触到ios用的是OC.对比之下, 感觉还是java用起 ...

  10. android 内存泄露之jni local reference table overflow (max=512)

    在android项目中要实现一个需求 为了性能的要求只能用c代码来实现功能. 这样就牺牲了java跨平台性. 通过加载.so的方式,把用c实现的模块集成到app中. android提供jni层,作为一 ...

随机推荐

  1. windwo访问linux文件夹方法

    windwo访问linux文件夹:是通过linux的samba来实现的: 安装samba需要安装samba-client.samba-common.smaba3个包. 一:安装rpm 现有一个服务器l ...

  2. 西门子PLC存储器、地址区

    S7-1500 CPU的存储器 1.内部集成的存储器:工作存储器,保持性存储器,系统存储器 2.外插的SIMATIC存储卡:装载存储器去 装载存储器:断电信息不丢失,主要存储项目中程序块,数据块,工艺 ...

  3. 【Codeforces 762A】 k-th divisor

    [题目链接] 点击打开链接 [算法] 我们知道,一个数的因子是成对出现的,一半小于等于sqrt(N),一半大于sqrt(N),因此,我们可以从 2..sqrt(N)枚举因子 [代码] #include ...

  4. [51nod 1129] 字符串最大值(kmp)

    传送门 题目大意 求一个字符串的前 缀出现次数乘以长度的最大值. 题解 暴力枚举每一个前缀求出现次数再乘以常数取最大 这样做会T几个点 看了老师的做法是任意前缀出现的次数,它的next也会出现这些次数 ...

  5. bzoj 2238 Mst —— 树剖+mn标记永久化

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2238 看了半天... 首先,想要知道每条边删除之后的替代中最小的那个: 反过来看,每条不在 ...

  6. 【iOS】KVC 和 KVO 的使用场景

    http://blog.csdn.net/chenglibin1988/article/details/38259865   Key Value Coding Key Value Coding是coc ...

  7. CodeForces 718C && HDU 3572 && Constellation

    Point 1. 区间乘以一个数/矩阵的幂时,不要用指数相加的方法. 而要用直接维护mulv[x]表示区间要乘多少. 不然的话,空加一个logn 2. 要点在于,冲突的点连边,形成二分图,对于在同一个 ...

  8. ASP.NET Core MVC 2.x 全面教程_ASP.NET Core MVC 23. 继续讲Tag Helpers 和复习View Component

    当条件为true就渲染,否则就不渲染 ‘ 判断用户的登陆 更好的一点是做一个TagHelper.把这些明显的C#代码都去掉.最终都是用html和属性的形式来组成一个最终的代码 属性名称等于Confit ...

  9. 洛谷 - P2261 - 余数求和

    https://www.luogu.org/problemnew/show/P2261 看了一下题解,取模运算可以换成减法来做. $a\%b=a-b*\lfloor\frac{a}{b}\rfloor ...

  10. 【Codeforces Round #411 (Div. 1)】Codeforces 804C Ice cream coloring (DFS)

    传送门 分析 这道题做了好长时间,题意就很难理解. 我们注意到这句话Vertices which have the i-th (1 ≤ i ≤ m) type of ice cream form a ...