G1从入门到放弃(二)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了G1从入门到放弃(二)相关的知识,希望对你有一定的参考价值。

参考技术A

上一篇文章主要讲了G1的理论知识,本篇文章会讲解在实际生产中如何读懂G1日志,以及介绍G1的参数配置。

通过使用 -XX:+PrintGCDetails 参数查看的Young GC日志如下:

① 四个关键信息

② 所有并行任务

③ 串行任务

④其他事项
其他事项共耗时3.7ms,其他事项包括选择CSet,处理已用对象,引用入ReferenceQueues,释放CSet中的region。

⑤各代变化

⑥ 这次回收耗时

①标明标记阶段开始

③并发标记

④ STW阶段

⑤ 这也是STW阶段
- GC cleanup : 这个阶段没有存活对象的Old Region和Humongous Region将被释放和清空。为了准备下次GC,在CSets中的Old Regions会根据他们的回收收益的大小排序。为了准备下一次标记,previous bitmaps 和 next bitmaps会被交换。同时并行线程会标记那些inital mark阶段生成的对象,以及至少存在一个存活对象的region的bitmap。
⑥这也是一个并发阶段

当并发标记完成后,在Young GC日志后面紧随着Mixed GC,下面是Mixed GC日志。可以看到Mixed GC日志和前面介绍的Young GC很相似,只有两个不同点:
1、第一行会表示这是一个Mixed GC
2、收集的集合里包含了老年代(Old Region),由并发标记阶段确定的。

Full GC的日志结果如下。

需要注意的是如果是几天一次Full GC,则是正常现象,但是每小时频繁GC就需要调优了。

建议大家开启 -XX:+PrintAdaptiveSizePolicy 和 -XX:+PrintTenuringDistribution 两个标签,可以帮助大家更好的分析日志。

Young GC开启 -XX:+PrintAdaptiveSizePolicy 之后的日志如下:

① 告诉我们有多少在dirty card队列里的cards等待被处理。并且展示了预计处理时间(包括了更新RSet和扫描RSet的时间);
② 有多少Region将被加入到这次GC中
③ 选择出CSets并且估算这次收集时间
④ 该行并不一定在Young GC日志中出现,如果花费在GC上的时间比应用线程大到一个阈值的时候,G1可以动态扩大堆大小。 如果你设置了最大堆和最小堆的大小相等,该行不会出现
⑤ 当并发标记开始时出现。

Young GC后面是并发回收日志。

Young GC日志中还可能存在关于Mixed GC的日志:

①告诉我们Mixed GC开始,原因是可回收垃圾百分比(22.62%)大于了我们的阈值(5%)。

下面是Mixed GC开启 -XX:+PrintAdaptiveSizePolicy 之后执行日志

① 该阶段包括CSet和一部分Young Region的选择
②描述Mixed GC时,Old Region被加入到CSet中。默认情况下,G1只把10%的Old Region加入到CSet中,通过配置 -XX:G1OldCSetRegionThresholdPercent=X 可以更改
③提供最终的CSet和停顿预测
④描述Mixed GC状态细节。在这个案例中,我们仍然有535个Old Region可以被回收,大约305363768字节,占整个堆大小的14.22%。由于仍然大于阈值,下个阶段回收仍然是Mixed GC。

下面是Full GC开启 -XX:+PrintAdaptiveSizePolicy 之后执行日志

① 没有空的Region用来分配对象,请求扩容堆
② 扩容需要多少空间。到目前为止还没有真正执行扩容。
③ 不会尝试扩容。因为没有可用的Region,所有要执行Full GC。
④ 在最小堆小于最大堆时出现的日志。G1 在一次Full GC后,尝试缩小堆到70%。这个百分比可以通过 -XX:InitiatingHeapOccupancyPercent (IHOP)调节,这个参数设置使用整个对的x%时,系统开始进行并行GC。注意是整个堆的百分比。
⑤ 堆正在被缩小,已经缩小了多少容量。

-XX:+PrintTenuringDistribution : 可以查看每次回收期间,Survivor区的分布信息。可以帮助我们查看对象年龄的变化。

上图主要从三个层面展示Survivor区:
-desired survivor size: 期望的Survivor大小。该值等于Survivor大小乘以TargetSurvivorRatio (默认50%)。

webpack 从入门到放弃

技术分享
问题: 1. 全局变量泛滥,2. 命名冲突, 3. 依赖关系管理,先去加载 a ,在去加载b, 否则就会报错;


二,模块化的初级阶段:立即执行函数
  1. var moduleA = function(){
  2. var a, b;
  3. return {
  4. message: function(c){
  5. alert(a+b+c)
  6. }
  7. }
  8. }()
  9. (function(window){
  10. // do something
  11. window.jQuery = window.$ = jQuery;
  12. })(window)

优点:模块内可以定义一些私有变量,缺点:仍然会污染全局变量,window.jquery ,没有解决模块依赖;


现代模块时代:
1. commonjs   , node 提出,同步不太适合浏览器,
  1.   var math = require(‘math‘);
  2. math.add(2, 3);
在服务器端,文件都是在硬盘中,而在浏览器中,文件需要网络穿过来,如果一个模块没传过来,整个应用都要停在那里等,浏览器假死;
2. requireJSAMD) , SeaJS ( CMD ),  
  1. require([‘math‘], function(math){
  2. math.add(2,3)
  3. })
异步,传入回调函数作为参数,等加载完成后执行;
3. ES6 Module, 目前比较流行;
  1. import math from ‘math‘;
  2. math.add(2, 3);

模块化的目的:高内聚,低耦合;


前端的模块加载:

前端模块要在 浏览器中运行,必经的过程就是从服务器到浏览器的传输;两个极端方式:1. 每一个模块都发起一个请求; 2. 所有模块打包成一个,只请求一次;
显然,都不好;按需加载是比较合适的;

前端的模块不仅仅有js,还有css,less, sass,图片,他们都是模块,都可以用require的方式加载;
  1. require(‘./style.css‘);
  2. require(‘./style.less‘);
  3. require(‘./style.jade‘);
  4. require(‘./image.png‘);
webpack 本身只能处理js ,如果想处理其他类型的文件,就需要用到 loader 进行转换;loader 本身是一个函数,接受源文件作为参数,返回转换后的结果;
loader的特点:
  1. 可以链式调用,我处理完了交给你接着处理,但是最后一个loader必须返回javascript 
  2. loader 可以同步或者异步执行
  3. loader 可以运行在 nodejs中,所以可能做任何事情
  4. loader 通过参数来传递配置
  5. 插件让loader 有更多的特性

  1. var webpack = require(‘webpack‘);
  2. module.exports = {
  3. entry: ‘./entry.js‘,
  4. output: {
  5. path: __dirname,
  6. filename: ‘bundle.js‘
  7. },
  8. module:{
  9. loaders: [
  10. {test: /\\.css$/, loader: ‘style-loader!css-loader‘}
  11. ]
  12. }
  13. }

添加插件,可以让loader 更加强大。插件有内置的,也有第三方的;
  1. var webpack = require(‘webpack‘);
  2. module.exports = {
  3. entry: ‘./entry.js‘,
  4. output: {
  5. filename: ‘bundle.js‘
  6. },
  7. module: {
  8. loaders: [
  9. { test:/\\.css$/, loader: ‘style-loader!css-loader‘}
  10. ]
  11. },
  12. plugin: [
  13. new webpack.BannerPlugin(‘dujuncheng created‘)
  14. ]
  15. }
 

1. 安装

/ dudu01  执行 npm init ,
  1. npm init
会把该文件夹变成一个项目,会自动生成一个package.json 配置文件;
  1. cnpm install webpack --save
为了把webpack 添加到项目依赖里面;
package.json 文件里面会多了一个字段:
  1. "dependencies": {
  2. "webpack": "^2.5.1"
  3. }

2. webpack 会自动将文件进行打包

安装好了以后,我们新建两个文件:index.html, entry.js
  1. // index.html
  2. <div id=‘app‘></div>
  3. <script src = ‘bundle.js‘>
  4. //entry.js
  5. document.getElementById(‘app‘).textContent = ‘hello‘
然后我们在控制台输入:
  1. webpack entry.js bundle.js

3. webpack 会自动分析 依赖,

webpack 会自动分析 entry.js里面依赖了哪些文件,会自动一起打包到bundle.js 里面;
我们新建一个bundle.js 文件,里面写的是:
  1. module.exports = ‘dujuncheng‘
在entry.js 里面引入:
  1. var name = require(‘./name‘);
  2. document.getElementById(‘app‘).textContent=‘hello‘+name
通过
  1. webpack entry.js bundle.js
再次打包,我们就可以把entry.js依赖的name.js 一起打包进入bundle.js

4. loader 

webpack 本身只能处理js ,如果想处理其他类型的文件,就需要用到 loader 进行转换;loader 本身是一个函数,接受源文件作为参数,返回转换后的结果;
如果我们想使用一个loader ,那么我们必须要手动安装;
  1. cnpm install css-loader style-loader --save
在package.json里面就会多了loader:
  1. "dependencies": {
  2. "css-loader": "^0.28.1",
  3. "style-loader": "^0.17.0",
  4. "webpack": "^2.5.1"
  5. }
我们新建webpack.config.js, 里面的内容是:
  1. module.exports = {
  2. entry: ‘./entry.js‘,
  3. output: {
  4. path: __dirname,
  5. filename: ‘bundle.js‘
  6. },
  7. module: {
  8. loaders:[
  9. { test:/\\.css$/, loader: ‘style-loader!css-loader‘ }
  10. ]
  11. }
  12. }
多了一个module 对象,里面有一个数组 loaders, 数组的每一项都是对象,{test: /\\.css$/, loader: ‘style-loader! css-loader‘}
这就是告诉 webpack, 只要是css , 就需要用这两个loader 进行处理;

我们新建一个style.css,一会要把它打包进 bundle.js
  1. body {
  2. background-color: red
  3. }
  1. //entry.js
  2. require(‘./style.css‘);
  3. document.getElementById(‘app‘).textContent = ‘dujuncheng‘ ;
我们把css  文件引入了js ,中间会自动用 css-loader , style-loader 进行处理;
  1. // 因为我们配置了webpack.config.js 配置文件,所以我们只要 webpack 就可以打包了
  2. webpack

5. source map

技术分享
 在没有用sourcemap的时候,我们在开发人员工具那里,看到了有 index.html 和 bundle.js
bundle. js 不用我们关心,因为是打包后的,我们需要关心的是 source-map
  1. webpack --devtool source-map
技术分享
 项目中会多了一个 bundle.js.map 的文件,我们的浏览器窗口下:
技术分享
 source-map 方便了我们的调试,在name.js 文件里面,添加: debugger ,我们就可以在那个位置打一个断点;
技术分享
 
如果我们不想在每一次的webpack 都带一个 devtool  我们可以在webpack.config.js 文件里面进行修改:
  1. module.exports = {
  2. entry: ‘./entry.js‘,
  3. output: {
  4. path: __dirname,
  5. filename: ‘bundle.js‘
  6. },
  7. devtool: ‘source-map‘,
  8. module: {
  9. loaders: [
  10. {
  11. test: /\\.css$/,
  12. loader: ‘style-loader!css-loader‘
  13. }
  14. ]
  15. }
  16. }

webpack 和 babel  进行配合
  1. cnpm install babel-loader babel-core babel-preset-es2015 --save-dev

code splitting
两个极端的的情况,我们把所有的文件都打包到一个文件里面,或者我们的每个文件都要分别打包;这两个都不好;
怎么做?
1. 分离业务代码和第三方库  [ vender ]
2. 分离css 文件
3. 按需加载  [ import() ]

第三方库更新较慢,并且可以锁版本,利用浏览器的缓存来加载第三方的库;
按需加载,用户访问了某一个路由的时候,再去加载相应的组件;

首先,我们想可视化的看到,我们的文件中是哪些比较占体积:webpack-bundle-analyzer
  1. npm install --save-dev webpack-bundle-analyzer
  2. //webpack.config.js
  3. var BundleAnalyzerPlugin = require(‘webpack-bundle-analyzer‘).BundleAnalyzerPlugin;
  4. // ...
  5. plugins: [new BundleAnalyzerPlugin()]
  6. // ...
通过这个插件,我们就可以很直观的分析啦;

分离第三方的库:我们的思路是:把node_module 里面的用到的 js插件,都放到vender.js 里面 
用webpack 自带的 commonChunkPlugin:
  1. new webpack.optimize.CommonsChunkPlugin({
  2. name: ‘vendor‘,
  3. minChunks: ({ resource }) => (
  4. resource && resource.indexOf(‘node_modules‘) >= 0 && resource.match(/\\.js$/))
  5. }),


按需加载
很简单,需要改两个地方:路由声明组件的那个地方,output的文件名;
1. 路由声明组件:
  1. // import test1 from ‘@/components/test1‘
  2. // import test2 from ‘@/components/test2‘
  3. // import test3 from ‘@/components/test3‘
  4. const test1 = () => import(
  5. /* webpackChunkName: "Emoji" */
  6. ‘@/components/test1‘)
  7. const test2 = () => import(
  8. /* webpackChunkName: "Emoji" */
  9. ‘@/components/test2‘)
  10. const test3 = () => import(
  11. /* webpackChunkName: "Emoji" */
  12. ‘@/components/test3‘)
2. chunkFilename修改
  1. filename: ‘[name].js‘,
  2. chunkFilename: ‘[name].chunk.js‘,
如果你用了 Babel ,就需要装上这个插件:babel plugin syntax dynamic import 来解析 import() 语法。修改 .babelrc :
  1. {
  2. "plugins": ["syntax-dynamic-import"]
  3. }






















































以上是关于G1从入门到放弃(二)的主要内容,如果未能解决你的问题,请参考以下文章

《Java从入门到放弃》JavaSE入门篇:面向对象语法二(入门版)

gentoo从入门到放弃

cmake从入门到放弃

webpack 从入门到放弃

weex从入门到放弃

API网关从入门到放弃