/**
* Creates a {@link RefWatcher} that works out of the box, and starts watching activity
* references (on ICS+).
*/
public static RefWatcher install(Application application) {
return install(application, DisplayLeakService.class,
AndroidExcludedRefs.createAppDefaults().build());
}
这个函数内部直接调用了另外一个重载的函数
/**
* Creates a {@link RefWatcher} that reports results to the provided service, and starts watching
* activity references (on ICS+).
*/
public static RefWatcher install(Application application,
Class extends AbstractAnalysisResultService> listenerServiceClass,
ExcludedRefs excludedRefs) {
//判断是否在Analyzer进程里
if (isInAnalyzerProcess(application)) {
return RefWatcher.DISABLED;
}
enableDisplayLeakActivity(application);
HeapDump.Listener heapDumpListener =
new ServiceHeapDumpListener(application, listenerServiceClass);
RefWatcher refWatcher = androidWatcher(application, heapDumpListener, excludedRefs);
ActivityRefWatcher.installOnIcsPlus(application, refWatcher);
return refWatcher;
}
public static boolean isInServiceProcess(Context context, Class extends Service> serviceClass) {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo;
try {
packageInfo = packageManager.getPackageInfo(context.getPackageName(), GET_SERVICES);
} catch (Exception e) {
Log.e("AndroidUtils", "Could not get package info for " + context.getPackageName(), e);
return false;
}
String mainProcess = packageInfo.applicationInfo.processName;
ComponentName component = new ComponentName(context, serviceClass);
ServiceInfo serviceInfo;
try {
serviceInfo = packageManager.getServiceInfo(component, 0);
} catch (PackageManager.NameNotFoundException ignored) {
// Service is disabled.
return false;
}
if (serviceInfo.processName.equals(mainProcess)) {
Log.e("AndroidUtils",
"Did not expect service " + serviceClass + " to run in main process " + mainProcess);
// Technically we are in the service process, but we're not in the service dedicated process.
return false;
}
//查找当前进程名
int myPid = android.os.Process.myPid();
ActivityManager activityManager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.RunningAppProcessInfo myProcess = null;
for (ActivityManager.RunningAppProcessInfo process : activityManager.getRunningAppProcesses()) {
if (process.pid == myPid) {
myProcess = process;
break;
}
}
if (myProcess == null) {
Log.e("AndroidUtils", "Could not find running process for " + myPid);
return false;
}
return myProcess.processName.equals(serviceInfo.processName);
}
private final Executor watchExecutor;
private final DebuggerControl debuggerControl;
private final GcTrigger gcTrigger;
private final HeapDumper heapDumper;
private final Set retainedKeys;
private final ReferenceQueue
watchExecutor: 执行内存泄露检测的executor
debuggerControl :用于查询是否正在调试中,调试中不会执行内存泄露检测
queue : 用于判断弱引用所持有的对象是否已被GC。
gcTrigger: 用于在判断内存泄露之前,再给一次GC的机会
headDumper: 用于在产生内存泄露室执行dump 内存heap
heapdumpListener: 用于分析前面产生的dump文件,找到内存泄露的原因
excludedRefs: 用于排除某些系统bug导致的内存泄露
retainedKeys: 持有那些呆检测以及产生内存泄露的引用的key。
接下来,我们来看看watch函数背后是如何利用这些工具,生成内存泄露分析报告的。
public void watch(Object watchedReference, String referenceName) {
checkNotNull(watchedReference, "watchedReference");
checkNotNull(referenceName, "referenceName");
//如果处于debug模式,则直接返回
if (debuggerControl.isDebuggerAttached()) {
return;
}
//记住开始观测的时间
final long watchStartNanoTime = System.nanoTime();
//生成一个随机的key,并加入set中
String key = UUID.randomUUID().toString();
retainedKeys.add(key);
//生成一个KeyedWeakReference
final KeyedWeakReference reference =
new KeyedWeakReference(watchedReference, key, referenceName, queue);
//调用watchExecutor,执行内存泄露的检测
watchExecutor.execute(new Runnable() {
@Override public void run() {
ensureGone(reference, watchStartNanoTime);
}
});
}
public final class AndroidWatchExecutor implements Executor {
//....
private void executeDelayedAfterIdleUnsafe(final Runnable runnable) {
// This needs to be called from the main thread.
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override public boolean queueIdle() {
backgroundHandler.postDelayed(runnable, DELAY_MILLIS);
return false;
}
});
}
}
void ensureGone(KeyedWeakReference reference, long watchStartNanoTime) {
long gcStartNanoTime = System.nanoTime();
//计算从调用watch到进行检测的时间段
long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
//根据queue移除已被GC的对象的弱引用
removeWeaklyReachableReferences();
//如果内存已被回收或者处于debug模式,直接返回
if (gone(reference) || debuggerControl.isDebuggerAttached()) {
return;
}
//如果内存依旧没被释放,则再给一次gc的机会
gcTrigger.runGc();
//再次移除
removeWeaklyReachableReferences();
if (!gone(reference)) {
//走到这里,认为内存确实泄露了
long startDumpHeap = System.nanoTime();
long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
//dump出heap报告
File heapDumpFile = heapDumper.dumpHeap();
if (heapDumpFile == HeapDumper.NO_DUMP) {
// Could not dump the heap, abort.
return;
}
long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
heapdumpListener.analyze(
new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
gcDurationMs, heapDumpDurationMs));
}
}
private boolean gone(KeyedWeakReference reference) {
return !retainedKeys.contains(reference.key);
}
private void removeWeaklyReachableReferences() {
// WeakReferences are enqueued as soon as the object to which they point to becomes weakly
// reachable. This is before finalization or garbage collection has actually happened.
KeyedWeakReference ref;
while ((ref = (KeyedWeakReference) queue.poll()) != null) {
retainedKeys.remove(ref.key);
}
}
//关键字的使用探讨/*访问关键词private 只能在本类中访问public 只能在本工程中访问protected 只能在包中和子类中访问默认的 只能在包中访问*//*final 类 方法 变量 final 类 不能被继承 final 方法 不能被子类覆盖,但可以继承 final 变量 只能有一次赋值,赋值后不能改变 final 不能用来修饰构造方法*///this()
What’s new in Zabbix 2.0?
去年开始使用Zabbix的时候,是1.8.X的版本,今年Zabbix已经跨入了2.0的时代。看了2.0的release notes,和performance相关的有下面几个:
:: Performance improvements::Trigger related da
修改jboss端口
%JBOSS_HOME%\server\{服务实例名}\conf\bindingservice.beans\META-INF\bindings-jboss-beans.xml
中找到
<!-- The ports-default bindings are obtained by taking the base bindin
@echo off
::演示:删除指定路径下指定天数之前(以文件名中包含的日期字符串为准)的文件。
::如果演示结果无误,把del前面的echo去掉,即可实现真正删除。
::本例假设文件名中包含的日期字符串(比如:bak-2009-12-25.log)
rem 指定待删除文件的存放路径
set SrcDir=C:/Test/BatHome
rem 指定天数
set DaysAgo=1
HTML5的video和audio标签是用来在网页中加入视频和音频的标签,在支持html5的浏览器中不需要预先加载Adobe Flash浏览器插件就能轻松快速的播放视频和音频文件。而html5media.js可以在不支持html5的浏览器上使video和audio标签生效。 How to enable <video> and <audio> tags in