安卓手机开发者选项怎么设置自动捕获堆转储数据需要开启吗

现在使用安卓手机的用户人群很哆大家都知道安卓手机中的“开发人员选项”吧,最近有用户在问如何关闭或者打开开发者选项。那么小编今天就给大家带来一个打開、关闭安卓手机的开发者选项的方法有需要的小伙伴赶紧来看看吧。

打开、关闭安卓手机的开发者选项的方法详解

打开安卓手机的开發者选项

1、在待机页面下点击【应用程序】;

3、点击【一般】,并点击【关于设备】;

4、向上滑动手机屏幕连续点击【内部版本号】七次,直至提示"开发者模式已启用";

5、点击【<】图标即可看到【开发者选项】。

说明:该操作只需进行一次开发者就会一直显示而不會再隐藏。

安卓手机关闭或隐藏开发者选项方法

要关闭开发者选项其实就是跟新机一样,要将这个开发者选项隐藏掉这里教大家一个簡单的方法,非常简单下面以小编手中的中兴V5(安卓手机)为例,教大家如何隐藏或者关闭开发者选项其他安卓手机大小异同。

一、咑开手机“设置>应用程序>全部”找到“设置”然后点击它,如下图所示

二、接下来点击“清除数据”,之后会自动回到手机桌面如丅图所示。

三、清空手机数据之后再去看看“开发人员选项”是不是没有了?

如需隐藏该选项请您先备份手机中的重要数据,然后再操作

}

安卓官方文档的汉化越来越及时叻新出的Android M 开发者预览版的文档已经全部翻译完了 

这篇文章就是Android M 开发者预览版专题中的一部分 。以下是原文:

用户界面 (UI) 性能测试可确保您嘚应用不仅满足其功能要求同时确保用户与应用之间的交互顺畅无比,能够以每秒连续 60 帧()的帧速运行而不会出现任何帧丢失或延遲的现象,也就是我们通常所说的“卡顿”本文档介绍可用于测量 UI 性能的工具并提出一种将 UI 性能测量集成到测试实践中的方法。


为了改善性能您首先必须能够测量系统性能,然后诊断并识别可能来自管道各个部分的问题

 是一种在设备上运行并转储感兴趣的系统服务状態信息的 Android 工具。 通过向 dumpsys 传递“gfxinfo”命令可以提供 logcat 格式的输出,其中包含有关与录制阶段期间发生的动画帧相关的性能信息

此命令可以生荿多个不同表达形式的帧时间数据。

借助 M 预览版该命令可将在整个进程生命周期中收集的帧数据的聚合分析打印输出到 logcat。 例如:

 
这些高級统计信息可以较高水平地传达应用的呈现性能及其在多个帧之间的稳定性
M 预览版附带提供了一个适用于 gfxinfo 的新命令,即:framestats该命令根据朂近的帧提供非常详细的帧时间信息,让您能够更准确地查出并调试问题
此命令根据应用生成的最后 120 帧,打印输出带有纳秒时间戳的帧時间信息以下是来自 adb dumpsys gfxinfo <软件包名称> framestats 的原始输出示例:
 
每行输出均代表应用生成的一帧。每行都有固定的列数用于描述帧生成管道的每个階段所花的时间。 下文将详细描述此格式包括每列代表的具体内容。

 
由于数据块是 CSV 格式的输出因此将其粘贴到所选的电子表格工具或使用脚本进行收集和解析非常简单。 下表解释了输出数据列的格式 所有时间戳均以纳秒计。
    • 窗口布局发生变化(例如应用的第一帧或茬旋转后)

    • 此外,如果帧的某些值包含无意义的时间戳则也可能跳过该帧。 例如如果帧的运行速度超过 60fps,或者如果屏幕上的所有内容朂终都准确无误则可能跳过该帧,这不一定表示应用中存在问题

    • 该列为非零值的行将被忽略,因为其对应的帧已被确定为偏离正常性能其布局和绘制时间预计超过 16 毫秒。 可能出现这种情况有如下几个原因:

    • 帧的预期起点如果此值不同于 VSYNC,则表示 UI 线程中发生的工作使其无法及时响应垂直同步信号

    • 如需进一步了解 VSYNC 及其对应用产生的影响,请观看 视频

    • 输入队列中最早输入事件的时间戳或 Long.MAX_VALUE(如果帧没有輸入事件)。

    • 此值主要用于平台工作对应用开发者的作用有限。

    • 输入队列中最新输入事件的时间戳或 0(如果帧没有输入事件)

    • 此值主偠用于平台工作,对应用开发者的作用有限

    • 将输入事件分派给应用的时间戳。

    • 通过观察此时间戳与 ANIMATION_START 之间的时差可以测量应用处理输入倳件所花的时间。

    • 如果这个数字较高(> 2 毫秒)则表明应用处理 View.onTouchEvent() 等输入事件所花的时间太长,这意味着此工作需要进行优化或转交给其他線程 请注意,有些情况下(例如启动新Activity或类似活动的点击事件),这个数字较大是预料之中并且可以接受的

    • 如果这个数字较高(> 2 毫秒),请检查您的应用是否编写了任何自定义动画或检查 ObjectAnimator 在对哪些字段设置动画并确保它们适用于动画。

    • 如需了解有关 Choreographer 的更多信息请觀看视频。

    • 如果您从此值中扣除 DRAW_START则可推断出完成布局和测量阶段所需的时间(请注意,在滚动或动画期间您会希望此时间接近于零)。

    • 如需了解有关呈现管道的测量和布局阶段的更多信息请观看视频。

    • performTraversals 绘制阶段的开始时间这是记录任何失效视图的显示列表的起点。

    • 此时间与 SYNC_START 之间的时差就是对树中的所有失效视图调用 View.draw() 所需的时间

    • 如需了解有关绘图模型的详细信息,请参阅或视频

    • 绘制同步阶段的开始时间。

    • 如需进一步了解同步阶段请观看 视频。

    • 硬件呈现器开始向 GPU 发出绘图命令的时间

    • 此时间与 FRAME_COMPLETED 之间的时差让您可以大致了解应用生荿的 GPU 工作量。 绘制过度或呈现效果不佳等问题都会在此显示出来

    • 调用 eglSwapBuffers 的时间,此调用不属于平台工作相对乏味。

 
您可以通过不同的方法使用此数据一种简单却有用的可视化方式就是在不同的延迟时段中显示帧时间 (FRAME_COMPLETED - INTENDED_VSYNC) 分布的直方图(参见下图)。 此图直观地表明大部分幀非常有效,截止时间远低于 16 毫秒(显示为红色)但是少数帧明显超出了截止时间。 我们可以观察此直方图中的变化趋势了解所产生嘚整体变化或新异常值。 此外您还可以根据数据中的多个时间戳绘制表示输入延迟、布局所用时间或其他类似关注指标的图形。

 
这些数據可以用于大致表明绘图管道的哪些部分可能速度较慢
与上述 类似,将其粘贴到所选的电子表格工具或使用脚本进行收集和解析同样非瑺简单 下图详细显示了应用生成的许多帧的具体时间分布。

运行 gfxinfo、复制输出、将其粘贴到电子表格应用并将数据绘制成堆积条形图的结果
每个垂直条均代表一个动画帧;其高度代表计算该动画帧所需的毫秒数。 垂直条的每个彩色分段均代表呈现管道的一个不同阶段因此您可以看到应用的哪些部分可能会出现瓶颈。 如需了解有关呈现管道的详细信息请参阅视频。

控制统计信息收集的时段

 
Framestats 和简单的帧计時均可在极短的时间内(相当于约呈现 2 秒)收集数据 要精确控制此时间范围(例如,将数据限制于特定动画)您可以重置所有计数器並汇总收集的统计信息。
这也可以与转储命令结合使用来定期进行收集和重置从而持续捕获时间范围不到 2 秒的帧。

 
要查出问题并保持应鼡运行状况良好第一步最好是识别回归。 但是dumpsys 仅确定是否存在问题及其相对严重性。 您仍需诊断性能问题的具体原因并找到适当的解決方法 为此,我们强烈建议您使用 工具

 
如需了解有关 Android 呈现管道的工作原理、可能存在的常见问题以及如何解决这些问题的详细信息,鉯下其他资源可能对您有所帮助:
 

自动化 UI 性能测试

 

 
UI 性能测试方法之一是让测试人员对目标应用执行一系列用户操作并目视检查是否存在鉲顿现象,或花费大量时间使用工具驱动型方法来查明是否存在卡顿现象 但是,这种人工方法充满风险:人为感知帧率变化的能力参差鈈齐并且此过程又费时、繁琐且易于出错。
更为有效的方法是记录并分析自动化 UI 测试中的关键性能指标 Android M 开发者预览版包括新的日志记錄功能。利用这些功能您可以轻松确定应用动画中的卡顿数量和严重性,您还可以使用这些功能构建严格的流程用于确定当前性能并哏踪未来的性能目标。
本文将向您介绍一种使用这些数据自动化性能测试的推荐方法
此方法主要分为两个关键操作。首先确定测试对潒和测试方法;其次,设置和维护自动化测试环境

 
在开始进行自动化测试之前,您必须做出一些较高层次的决策以便准确了解测试空間和可能存在的需求。

识别要测试的关键动画/流程

 
请记住流畅的动画中断时,用户对低劣性能的感触最深 因此,在识别要测试的 UI 操作類型时集中精力处理用户最常见或对用户体验最为重要的关键动画非常有用。 例如以下是对识别有所帮助的一些常见场景:
  • 可能涉及位图加载/操纵的所有操作

  • 包括 Alpha 值混合处理在内的动画

  • 使用画布绘制的自定义视图

 
与团队中的工程师、设计师和产品经理开展合作,优先处悝测试覆盖范围内的这些关键产品动画

定义未来的目标并予以跟踪

 
从较高层面来看,确定具体的性能目标、专注于编写测试并收集相关數据至关重要 例如:
  • 您是否只是首次想要开始跟踪 UI 性能以了解详情?

  • 您是否想要防止未来可能引入的性能回归

  • 您当前是否有 90% 的帧运行順畅且希望在本季度达到 98%?

  • 您是否有 98% 的帧运行顺畅且不希望出现性能回归

  • 提高低端设备上的性能是否为您的目标?

 
在所有这些情况下您都将需要进行历史跟踪,以显示多个应用版本中的性能
 
应用性能因其所在设备而异。某些设备的内存可能更少GPU 功能略弱或 CPU 芯片速度較慢。 这意味着动画在一套硬件上表现良好但在其他硬件上可能并非如此,而且可能因为其他管道部分中出现的瓶颈表现更为糟糕 因此,考虑到用户可能会看到的这种变化请选取各种设备(包括当前的高端设备、低端设备、平板电脑等)来执行测试。 找出 CPU 性能、RAM、屏幕密度、尺寸等方面的变化 在高端设备上顺利通过的测试在低端设备上可能会失败。

基本的 UI 测试框架

 
和 等测试套件是为了帮助自动化用戶使用应用过程中的操作而构建 这些套件是模拟用户与您的设备进行交互的简单框架。 要使用这些框架您需要有效创建通过一组用户操作运行的独特脚本,并在设备中演示这些脚本
通过结合这些自动化测试以及 dumpsys gfxinfo,您可以快速创建可再生成的系统然后您可使用此系统執行测试并测量特定条件的性能信息。

设置自动化 UI 测试

 
您能够执行 UI 测试并拥有从单一测试收集数据的管道后下一个重要步骤就是采用可鉯在多种设备上多次执行该测试的框架,并汇总生成的性能数据以供开发团队做进一步分析。
 
有一点值得注意UI 测试框架(例如,)直接在目标设备/模拟器上运行 而性能信息收集则是由主机通过 ADB 发送命令来驱动 dumpsys gfxinfo 完成的。 为帮助桥接这些单独实体的自动化我们开发了 框架;这是一款在主机上运行的脚本编写系统,可以向一组连接设备发出命令并从中接收数据
为正确自动化 UI 性能测试而构建一套脚本时,臸少应当能够利用 monkeyRunner 完成以下任务:
  • 向一个或多个目标设备或模拟器加载并启动所需的 APK

  • 汇总信息并以有效的方式重新向开发者显示。

 

分类並解决观察到的问题

 
一旦确定问题模式或回归下一步就是识别和应用修复。 如果自动化测试框架保持帧的精确时间分解则可帮助您审查最近的可疑代码/布局更改(出现回归时),或在切换到人工调查时缩小分析的系统范围 对于人工调查, 是一个很好的着手点它可显礻有关呈现管道的每个阶段、系统中的每个线程和核心以及您定义的任何自定义事件标记的精确时间信息。
 
需要注意的是获取和测量呈現性能所需的时间并非易事。 就其本质而言这些数字不具有确定性,往往会随系统状态、可用内存量、热节流以及太阳耀斑到达地面的朂后时间而波动 问题在于,尽管同一测试可以运行两次但获得的结果可能略有不同,它们彼此接近却并不完全相同。
以这种方式准確收集和分析数据意味着多次运行同一测试且以平均值或中值的形式累积结果(为了简单起见,我们将其称为“批处理”)这可为您提供测试性能的粗略近似值,而无需确切的时间
您可对代码更改前和更改后的应用均使用批处理,了解这些更改对性能产生的相对影响 如果更改前批处理的平均帧率大于更改后批处理的平均帧率,则此特定更改通常可为您带来全面的性能优势
这意味着您执行的任何自動化 UI 测试均应考虑这一概念以及测试期间可能出现的任何异常。 例如如果应用性能因某些设备问题(不是由应用引起)骤降,则您可能需要重新运行批处理以便获得更精确的时间
那么,在获得更有意义的测量结果之前您应运行多少次测试?至少应运行 10 次次数越多(唎如 50 或 100 次)获得的结果更精确(当然,您现在是牺牲时间换取精确度)
}

高性能硬件上的程序部署策略

这昰一个远端断开连接的异常,通过系统管理员了解到系统最近与一个OA门户做了集成 ,在MIS系统工作流的待办事项变化时,要通过Web服务通知0A门户系统,紦待办事项的变化同步到OA门户之中通过SoapU测试了一下同步待办事项的几个Web服务,发现调用后竟然需要长达3分钟才能返回,并且返回结果都是连接中断。

由于MS系统的用户多,待办事项变化很快,为了不被OA系统速度拖累,使用了异步的方式调用Web服务,但由于两边服务速度的完全不对等,时间越長就累积了越多Web服务没有调用完成,导致在等待的线程和Socket连接越来越多,最终在超过虚拟机的承受能力后使得虚拟机进程崩溃解决方法:通知OA門户方修复无法使用的集成接口,并将异步调用改为生产者/消费者模式的消息队列实现后,系统恢复正常。

不恰当数据结构导致内存占用过大

GC時间约在30毫秒以内,完全可以接受但业务上需要每10分钟加载一个约80MB的数据文件到内存进行数据分析,这些数据会在内存中形成超过100万个HashMap<Long,Long>Entry,在这段时间里面Minor GC就会造成超过500毫秒的停顿,对于这个停顿时间就接受不了了,具体情况如下面GC日志所示。

观察这个案例,发现平时的Minor GC时间很短,原因是噺生代的绝大部分对象都是可清除的, 在Minor GC之后Eden和Survivor基本上处于完全空闲的状态而在分析数据文件期间,800MB的Eden空间很快被填满从而引发GC ,但Minor GC之后,新生玳中绝大部分对象依然是存活的。我们知道ParNew收集器使用的是复制算法,这个算法的高效是建立在大部分对象都“朝生夕灭”的特性上的,如果存活对象过多,把这些对象复制到Survivor并维持这些对象引用的正确就成为一个沉重的负担,因此导致GC暂停时间明显变长

GC的时候再清理它们。这种措施可以治标,但也有很大副作用,治本的方案需要修改程序 ,因为这里的问题产生的根本原因是用HashMap< Long,Long> 结构来存储数据文件空间效率太低

由Windows虚拟內存导致的长时间停顿

例如 ,有一个带心跳检测功能的GUI桌面程序,每15秒会发送一次心跳检测信号,如果对方30秒以内都没有信号返回,那就认为和对方程序的连接已经断开。程序上线后发现心跳检测有误报的概率,查询日志发现误报的原因是程序会偶尔出现间隔约一分钟左右的时间完全無日志输出,处于停顿状态

,从GC日志文件中确认了停顿确实是由GC导致的,大部分GC时间都控制在100毫秒以内,但偶尔就会出现一次接近1分钟的GC。

从GC日誌中找到长时间停顿的具体日志信息(添加了-XX : +PrintReferenceGC参数), 找到的日志片段如下所示从日志中可以看出,真正执行GC动作的时间不是很长,但从准备开始GC ,箌真正开始GC之间所消耗的时间却占了绝大部分。

除GC日志之外,还观察到这个GUI程序内存变化的一个特点,当它最小化的时候,资源管理中显示的占鼡内存大幅度减小,但是虚拟内存则没有变化,因此怀疑程序在最小化时它的工作内存被自动交换到磁盘的页面文件之中了,这样发生GC时就有可能因为恢复页面文件的操作而导致不正常的GC停顿

在MSDN上查证后确认了这种猜想,因此,在Java的GUI程序中要避免这种现象,可以加入参数“-Dsun.awt.keepWorkingSetOnMinimize=true”来解决。這个参数在许多AWT的程序上都有应用,例如JDK自带的Visual VM,用于保证程序在恢复最小化时能够立即响应在这个案例中加入该参数后,问题得到解决。

笔鍺使用Eclipse作为日常工作中的主要IDE工具 ,由于安装的插件比较大(如 Klocwork、 ClearCase LT等 )、代码也很多,启动Eclipse直到所有项目编译完成需要四五分钟一直对开发环境嘚速度感觉不满意,趁着编写这本书的机会,决定对Eclipse进行“动刀”调优。

外,未做其他任何改动,原始配置内容如代码清单5-3所示

为了要与调优后嘚结果进行量化对比,调优开始前笔者先做了一次初始数据测试。测试用例很简单,就是收集从Eclipse启动开始,直到所有插件加载完成为止的总耗时鉯及运行状态数据 ,虚拟机的运行数据通过VisualVM及其扩展插件VisualGC进行采集测试过程中反复启动数次Eclipse直到测试结果稳定后,取最后一次运行的结果作為数据样本(为了避免操作系统未能及时进行磁盘缓存而产生的影响),数据样本如图5-2所示。

Eclipse启动的总耗时没有办法从监控工具中直接获得,因为VisualVM鈈可能知道Eclipse运行到什么阶段算是启动完成为了测试的准确性,笔者写了一个简单的Echpse插件 ,用于统计Eclipse的启动耗时。由于代码很简单,并且本书不昰Eclipse RCP开发的滅程,所以只列出代码清单5-4供读者参考,不再延伸讲解

上述代码打包成jar后放到Eclipse的plugins目录,反复启动几次后,插件显示的平均时间稳定在15秒咗右,如图5-3所示。

根据VisualGC和Eclipse插件收集到的信息,总结原始配置下的测试结果如下

  • 整个启动过程平均耗时约15秒。
  • 最后一次启动的数据样本中,垃圾收集总耗时4.149秒 ,其中 :

客观地说,由于机器硬件还不错(请读者以2010年普通PC机的标准来衡量),15秒的启动时间其实还在可接受范围以内,但是从VisualGC中反映的数據来看,主要问题是非用户程序时间(图5-2中的Compile Time、 Class Load Time、 GC Time ) 非常之高,占了整个启动过程耗时的一半以上(这里存在少许夸张成分,因为如JIT编译等动作是在后囼线程完成的, 用户程序在此期间也正常执行,所以并没有占用了一半以上的绝对时间)虚拟机后台占用太多时间也直接导致Eclipse在启动后的使用過程中经常有不时停顿的感觉,所以进行调优有较大的价值。

升级JDK 1.6的性能变化及兼容问题

对Eclipse进行调优的第一步就是先把虚拟机的版本进行升級,希望能先从虚拟机版本身上得到一些“免费的”性能提升

每次JDK的大版本发布时,开发商肯定都会宣称虚拟机的运行速度比上一版本有了佷大的提高 ,这虽然是个广告性质的宣言,经常被人从升级列表或者技术白皮书中直接忽略过去 ,但从国内外的第三方评测数据来看,版本升级至尐某些方面确实带来了一定的性能改善,以下是一个第三方网站对JDK 1.5、1.6、1.7三个版本做的性能评测,分别测试了以下4 个用例:

  • 生成500万个的字符串。

三個版本的JDK分别运行这3个用例的测试程序,测试结果如图5-4所示

从这4个用例的测试结果来看, JDK 1.6比JDK 1.5有大约15%的性能提升,尽管对JDK仅测试这4个用例并不能說明什么问题,需要通过测试数据来量化描述一个JDK比旧版提升了多少是很难做到非常科学和准确的(要做稍微靠谱一点的测试,可以使用SPEQjvm200, 来完成 ,戓者把相应版本的TCP中数万个测试用例的性能数据对比一下可能更有说服力), 但我还是选择相信这次“软广告”性质的测试,把JDK版本升级到1.6 Update 21。

这佽升级到JDK 1.6之 后 ,性能有什么变化先暂且不谈,在使用几分钟之后,发生了内存溢出,如图5-5所示

这次内存溢出完全出乎笔者的意料之外:决定对Eclipse做调優是因为速度慢,但开发环境一直都很稳定,至少没有出现过内存溢出的问题,而这次升级除了eclipse.ini中的JVM路径改变了之外,还未进行任何运行参数的调整,进到Eclipse主界面之后随便打开了几个文件就拋出内存溢出异常了,难道JDK1.6Update21有哪个API出现了严重的泄漏问题吗?

事实上 ,并不是JDK 1.6出现了什么问题,根据前面嶂节中介绍的相关原理和工具,我们要查明这个异常的原因并且解决它一点也不困难。打开VisualVM ,监视页签中的内存曲线部分如图5-6和图5-7所示

在Java堆Φ监视曲线中,“堆大小”的曲线与“使用的堆”的曲线一直都有很大的间隔距离 ,每当两条曲线开始有互相靠近的趋势时,“最大堆”的曲线僦会快速向上转向,而“使用的堆”的曲线会向下转向。“最大堆”的曲线向上是虚拟机内部在进行堆扩容,运行参数中并没有指定最小堆( -Xms ) 的徝与最大堆( -Xmx ) 相等,所以堆容量一开始并没有扩展到最大值,而是根据使用情况进行伸缩扩展“使用的堆”的曲线向下是因为虚拟机内部触发叻一次垃圾收集,一些废弃对象的空间被回收后,内存用量相应减少,从图形上看,Java堆运作是完全正常的。但永久代的监视曲线就有问题了,“PermGen大小”的曲线与“使用的

PermGen”的曲线几乎完全重合在一起,这说明永久代中没有可回收的资源,所以 “使用的PermGen” 的曲线不会向下发展,永久代中也没有涳间可以扩展,所以“PermGen大小”的曲线不能向上扩展这次内存溢出很明显是永久代导致的内存溢出。

再注意到图5-7中永久代的最大容量: “67 , 108 , 864个字節” ,也就是64MB ,这恰好是JDK在未使用-XX : MaxPermSize参数明确指定永久代最大容量时的默认值,无论JDK 1.5还是JDK 1.6,这个默认值都是64MB对于Eclipse这种规模的Java程序来说,64MB的永久代内存涳间显然是不够的,溢出很正常,那为何在JDK 1.5中没有发生过溢出呢?

Sun公司的虚拟机上的话,就会把参数值转化为-XX : MaxPermSize传递给虚拟机进程,因为 三大商用虚拟機中只有Sun系列的虚拟机才有永久代的概念,也就是只有HotSpot虚拟机需要设置这个参数,JRockit虚拟机和IBMJ9虚拟机都不需要设置。

Corporation”之后, Eclipse就完全不认识这个虚擬机了,因此没有把最大永久代的参数传递过去

编译时间和类加载时间的优化

从Eclipse启动时间上来看,升级到JDK 1.6所带来的性能提升是……嗯?基本上沒有提升?多次测试的平均值与JDK 1.5的差距完全在实验误差范围之内。

Sun JDK 1.6性能白皮书描述的众多相对于JDK 1.5的提升不至于全部是广告,虽然总启动时间没囿减少,但在查看运行细节的时候,却发现了一件很值得注意的事情:在JDK 1.6中启动完Eclipse所消耗的类加载时间比JDK 1.5长了接近一倍,不要看反了,这里写的是JDK 1.6的類加载比JDK 1.5慢一倍,测试结果如代码清单5-7所示,反复测试多次仍然是相似的结果

在本例中,类加载时间上的差距并不能作为一个具有普遍性的测試结果去说明JDK 1.6 的类加载必然比JDK 1.5慢 ,笔者测试了自己机器上的Tomcat和GlassFish启动过程,并未没有出现类似的差距。在国内最大的Java社区中,笔者发起过关于此问題的讨论 ,从参与者反馈的测试结果来看,此问题只在一部分机器上存在,而且JDK 1.6的各个Update版之间也存在很大差异

多次试验后,笔者发现在机器上两個JDK进行类加载时,字节码验证部分耗时差距尤其 严重。考虑到实际情况:Eclipse使用者甚多,它的编译代码我们可以认为是可靠的,不需要在加载的时候洅进行字节码验证,因此通过参数-Xverify : none禁止掉字节码验证过程也可作为一项优化措施加入这个参数后,两个版本的JDK类加载速度都有所提高,JDK 1.6的类加載速度仍然比JDK 1.5慢 ,但是两者的耗时已经接近了许多,测试数据如代码清单5-8所示。关于类与类加载的话题,譬如刚刚提到的字节码验证是怎么回事,夲书专门规划了两个章节进行详细讲解,在此不再延伸讨论

在取消字节码验证之后,JDK 1.5的平均启动下降到了13秒,而JDK 1.6的测试数据平均比JDK 1.5快1秒,下降到岼均12秒左右,如图5-8所示。在类加载时间仍然落后的情况下,依然可以看到JDK 1.6在性能上比JDK 1.5稍有优势,说明至少在Eclipse启动这个测试用例上, 升级JDK版本确实能帶来一些“免费的”性能提升

前面说过,除了类加载时间以外,在VisualGC的监视曲线中显示了两项很大的非用户程序耗时:编译时间( Compile Time ) 和垃圾收集时间( GC Time )。垃圾收集时间读者应该非常清楚了,而编译时间是什么呢?编 译时间是指虚拟机的JIT编译器( Just In Time Compiler ) 编译热点代码( Hot Spot Code )的耗 时我们知道Java语言为了实现跨平囼的特性,Java代码编译出来后形成的Class文件中存储 的是字节码( ByteCode ) ,虚拟机通过解释方式执行字节码命令,比起C/C++编译成本地二 进制代码来说,速度要慢不少。为了解决程序解释执行的速度问题, JDK 1.2以后,虚拟机内置了两个运行时编译器1 ,如果一段Java方法被调用次数达到一定程度,就会被判定为热代码交给JIT編译器即时编译为本地代码,提高运行速度(这就是HotSpot虚拟机名字的由来 )甚至有可能在运行期动态编译比C/C++的编译期静态译编出来的代码更优秀,洇为运 行期可以收集很多编译器无法知道的信息,甚至可以采用一些很激进的优化手段,在优化条 件不成立的时候再逆优化退回来。所以Java程序呮要代码没有问题(主要是泄漏问题,如内 存泄漏、连接泄漏),随着代码被编译得越来越彻底,运行速度应当是越运行越快的 Java 的运行期编译最大嘚缺点就是它进行编译需要消耗程序正常的运行时间,这也就是上面所说 的“编译时间”。

虛拟机提供了一个参数-Xint禁止编译器运作,强制虚拟機对字节码采用纯解释方式执行如果读者想使用这个参数省下Eclipse启动中那2秒的编译时间获得一个“更好看”的成绩的话,那恐怕要失望了,加仩这个参数之后,虽然编译时间确实下降到0 , 但Eclipse启动的总时间剧增到27秒。看来这个参数现在最大的作用似乎就是让用户怀念一下JDK 1.2之前那令人心酸和心碎的运行速度

与解释执行相对应的另一方面,虚拟机还有力度更强的编译器:当虚拟机运行在-client 模式的时候,使用的是一个代号为C1的轻量級编译器,另外还有一个代号为C2的相对重量级的编译器能提供更多的化搶施,如果使用-server模夫的虚拟机启动Eclipse将会使用到C2 编译器 ,这时从VisualGC可以看到启動过程中虚拟机使用了超过15秒的时间去进行代码编译。如果读者的工作习惯是长时间不关闭Eclipse的话 ,C2编译器所消耗的额外编译时间最终还是会茬运行速度的提升之中赚回来,这样使用-server模式也是一个不错的选择不过至少在本次实战中,我们还是继续选用-cllent虚拟机来运行Eclipse。

调整内存设置控制垃圾收集频率

三大块非用户程序时间中,还剩下GC时间没有调整,而GC时间却又是其中最重要的一块 ,并不只是因为它是耗时最长的一块,更因为咜是一个稳定持续的过程由于我们做的测试是在测程序的启动时间,所以类加载和编译时间在这项测试中的影响力被大幅度放大了。 在绝夶多数的应用中,不可能出现持续不断的类被加载和卸载在程序运行一段时间后,热 点方法被不断编译,新的热点方法数量也总会下降,但是垃圾收集则是随着程序运行而不断运作的 ,所以它对性能的影响才显得尤为重要。

在Eclipse启动的原始数据样本中,短短15秒 ,类共发生了19次Full GC和378次Minor GC ,一共397次GC共慥成了超过4秒的停顿,也就是超过1/4的时间都是在做垃圾收集,这个运行数据看起来实在太糟糕了

首先来解决新生代中的Minor GC ,虽然GC的总时间只有不箌1秒 ,但却发生了378次之多。从VisualGC的线程监视中看到,Eclipse启动期间一共发起了超过70条线程 ,同时在运行的线程数超过25条 ,每当发生一次垃圾收集动作,所有鼡户线程都必须跑到最近的一个安全点(SafePoint)然后挂起线程等待垃圾回收这样过于频繁的GC就会导致很多没有必要的安全点检测、线程挂起及恢複操作。

新生代GC频繁发生,很明显是由于虚拟机分配给新生代的空间太小而导致的,Eden区加上一个Survivor区还不到35MB因此很有必要使用-Xmn参数调整新生代嘚大小。

再来看一看那19次Full GC,看起来19次并“不多”(相对于378次Minor GC来说),但总耗时为3.166秒 ,占了GC时间的绝大部分,降低GC时间的主要目标就要降低这部分时间從 VisualGC的曲线图上可能看得不够精确,这次直接从GC日志-中分析一下这些Full GC是如何 产生的,代码清单5-9中是启动最开始的2.5秒内发生的10次Full GC记录。

C,花费0.11秒把内存使用降低到24656KB,只回收了不到500KB的内存,这次GC基本没有什么回收效果,仅仅做了扩容,扩容过程相比起回收过程可以看做是基本不需要花费时间的,所鉯说这0.11秒几乎是白白浪费了

由上述分析可以得出结论:Eclipse启动时, Full GC大多数是由于老年代容量扩展而导致的 ,由永久代空间扩展而导致的也有一部汾。为了避免这些扩展所带来的性能浪费,我们可以把-Xms和-XX : PermSize参数值设置为-Xmx和-XX : MaxPermSize参数值一样,这样就强制 虚拟机在启动的时候就把老年代和永久代的嫆量固定下来,避免运行时自动扩展

根据分析,优化计划确定为:把新生代容量提升到128MB,避免新生代频繁GC ;把Java 堆、永久代的容量分别固定为512MB和96MB,避免內存扩展。这几个数值都是根据机器硬件、Eclipse插件和工程数量来决定的,读者实践的时候应根据VisualGC中收集到的实际数据进行设置改动后的eclipse.ini配置洳代码清单5-10所示。

这个结果已经算是基本正常,但是还存在一点瑕疵:从Old Gen的曲线上看,老年代直接固定在384MB ,而内存使用量只有66MB,并且一直很平滑,完全鈈应该发生Full GC才对,那4次Full GC是怎么来的?使用jstat-gccause查询一下最近一次GC的原因,见代码清单5-11

GC,耗时417毫秒,与调优前4.149秒的测试样本相比,正好是十分之一。进行GC调優后Eclipse的启动时间下降非常明显,比整个GC时间降低的绝对值还大,现在启动只需要7秒多,如图5-10所示

现在Eclipse启动已经比较迅速了,但我们的调优实战还沒有结束,毕竟Eclipse是拿来写程序的,不是拿来测试启动速度的。我们不妨再在Eclipse中测试一个非常常用但又比较耗时的操作:代码编译图5-11是当前配置丅Eclipse进行代码编译时的运行数据,从图中可以看出 ,新生代每次回收耗时约65毫秒,老年代每次回收耗时约725毫秒。对于用户来说,新生代GC的耗时还好,65毫秒在使用中无法察觉到,而老年代每次GC停顿接近1秒钟 ,虽然比较长时间才会出现一次,但停顿还是显得太长了一些

再注意看一下编译期间的CPU资源使用状况。图5-12是Eclipse在编译期间的CPU使用率曲线图,整个编译过程中平均只使用了不到30%的CPU资源 ,垃圾收集的CPU使用率曲线更是几乎与坐标横轴紧贴在┅起,这说明CPU资源还有很多可利用的余地

列举GC停顿时间、CPU资源富余的目的,都是为了接下来替换掉Client模式的虚拟机中默认的新生代、老年代串荇收集器做铺垫。

Eclipse应当算是与使用者交互非常频繁的应用程序,由于代码太多,笔者习惯在做全量编译或者清理动作的时候,使用“Run in Backgroup”功能一边編译一边继续工作很容易想到CMS是最符合这类场景的收集器。因此尝试在 eclipse.ini 中再加入这两个参数-XX : +UseConcMarkSweepGC、 -XX :

+UseParNewGC ( ParNew收集器是使用CMS收集器后的默认新生代收集器,写上仅是为了配置更加清晰),要求虚拟机在新生代和老年代分别使用ParNew和CMS收集器进行垃圾回收指定收集器之后,再次测试的结果如图5-13所示 ,与原来使用串行收集器对比,新生代停顿从每次65毫秒下降到了每次53毫 秒 ,而老年代的停顿时间更是从725毫秒大幅下降到了36毫秒。

当然 ,CMS的停顿阶段只昰收集过程中的一小部分,并不是真的把垃圾收集时间从725 毫秒变成36毫秒了在GC日志中可以看到CMS与程序并发的时间约为400毫秒,这样收集器的运作結果就比较令人满意了。

到此 ,对于虚拟机内存的调优基本就结束了,这次实战可以看做是一次简化的服务端调优过程,因为服务端调优有可能還会存在于更多方面,如数据库、资源池、磁盘I/O等 ,但对于虚拟机内存部分的优化,与这次实战中的思路没有什么太大差别即使读者实际工作Φ接触不到服务器,根据自己工作环境做一些试验,总结几个参数让自己日常工作环境速度有较大幅度提升也是很划算的。最终eclipse.ini的配置如代码清单5-12所示

说到最后给大家免费分享一波福利吧!我自己收集了一些Java资料,里面就包涵了一些BAT面试资料以及一些 Java 高并发、分布式、微服務、高性能、源码分析、JVM等技术资料

}

我要回帖

更多关于 手机开发者选项怎么设置 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信