MockingBird

记录 Web 前端成长旅程


  • 首页

  • 分类

  • 归档

  • 标签

[译]在 Node.js 中监测内存泄露

发表于 2016-09-06   |   分类于 node.js   |  

偶然看到这篇关于node.js内存泄露监测的文章,自己对node.js对性能调试并不了解,所以翻译一下这篇感觉还不错我文章以增强自己对印象。
原文地址:http://www.nearform.com/nodecrunch/self-detect-memory-leak-node

在node.js里面追踪内存泄露并不是一件容易对事情。下面讨论一下通过借助“memwatch”(支持 node.js 版本:0.10.x), “heapdump”这两个模块,怎样在node.js程序内部让它自己追踪内存泄露。

内存泄露插图

首先,写一个简单的内存泄露案例:

1
2
3
4
5
6
7
8
9
10
11
12
var http = require('http');

var server = http.createServer(function (req, res) {
for (var i = 0; i < 1000; i++) {
server.on('request', function leakfunc() {});
}

res.end('Hello World\n');
}).listen(1333, '127.0.0.1');

server.setMaxListeners(0);
console.log('Server running at http://127.0.0.1:1333/. Progress PID:', process.pid);

每个请求都额外的创建了1000个监听器。

如果我们在shell中通过 while true; do curl http://127.0.0.1:1333/; done 命令,不断地发起请求,然后再另外一个shell窗口通过 top -pid <process pid> 可以看到 node 进程占用非常高的内存使用率,而且非常不稳定。

我们的 node 进程已经疯了。那么我们怎么诊断出问题来呢?

内存泄露监测

“memwatch” 模块是最好的内存泄露检查工具。首先,我们通过下面的命令安装这个模块:

1
npm install --save memwatch

然后,在我们的代码里调用它:

1
2
var memwatch = require('memwatch');
memwatch.setup();

同时,也要监听”leak”事件:

1
2
3
memwatch.on('leak', function(info) {
console.error('Memory leak detected: ', info);
});

现在当你再次运行上面的测试案例,我们可以在控制台看到下面的信息:

1
2
3
4
5
6
{
start: Fri Jan 02 2015 10:38:49 GMT+0000 (GMT),
end: Fri Jan 02 2015 10:38:50 GMT+0000 (GMT),
growth: 7620560,
reason: 'heap growth over 5 consecutive GCs (1s) - -2147483648 bytes/hr'
}

(注:由于我自己的 node.js 版本问题,导致无法安装 “memwatch“, 所以这个数据直接来源于原文)
memwatch 监测到了内存泄露!它定义内存泄露的标准为:

一个内存泄露事件会在堆中增加5个连续的垃圾回收行为时触发

查看 memwatch 了解更多。

内存泄露分析

现在我们已经发现了内存泄露,那么下一步我们在做的就是分析造成内存泄露的原因所在!
打个比方,我们可以在”leak”事件发生时把堆信息dump出来看看:

1
2
3
4
5
6
7
8
9
10
11
var hd;
memwatch.on('leak', function(info) {
console.error(info);
if (!hd) {
hd = new memwatch.HeapDiff();
} else {
var diff = hd.end();
console.error(util.inspect(diff, true, null));
hd = null;
}
});

这样我可以拿到下面的信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{ before: {
nodes: 244023,
time: Fri Jan 02 2015 12:13:11 GMT+0000 (GMT),
size_bytes: 22095800,
size: '21.07 mb' },
after: {
nodes: 280028,
time: Fri Jan 02 2015 12:13:13 GMT+0000 (GMT),
size_bytes: 24689216,
size: '23.55 mb' },
change: {
size_bytes: 2593416,
size: '2.47 mb',
freed_nodes: 388,
allocated_nodes: 36393,
details:
[ { size_bytes: 0,
'+': 0,
what: '(Relocatable)',
'-': 1,
size: '0 bytes' },
{ size_bytes: 0,
'+': 1,
what: 'Arguments',
'-': 1,
size: '0 bytes' },
{ size_bytes: 2856,
'+': 223,
what: 'Array',
'-': 201,
size: '2.79 kb' },
{ size_bytes: 2590272,
'+': 35987,
what: 'Closure',
'-': 11,
size: '2.47 mb' },
...

我们可以在两次 leak 事件看出堆增长了 2.47MB 的大小,然后是由闭包造成的。注意如果你指明了函数,那在这里有可能看到详细的造成内存泄露的函数名,这样我们就可以更方便的调试。

然后,在上面的例子中,我们只知道是有闭包造成的内存泄露,这并没有太大的作用。

所以,我们还要借助 heapdump。

heapdump

heapdump 可以把 V8 中的堆 dump 出来,然后你可以借助 Chrome 开发者工具进行分析。你可以在开发者工具中比较两个堆,这有助于你更好的定位内存泄露的原因。

下面我们开始在代码中使用 heapdump,我们在每一次 “leak” 事件被触发时,保存一份快照到硬盘上:

1
2
3
4
5
6
7
8
memwatch.on('leak', function(info) {
console.error(info);
var file = '/tmp/myapp-' + process.pid + '-' + Date.now() + '.heapsnapshot';
heapdump.writeSnapshot(file, function(err){
if (err) console.error(err);
else console.error('Wrote snapshot: ' + file);
});
});

这样,我们再次运行测试案例的时候,我们可以看到 /tmp 目录下多了一些 .heapsnapshot 文件。我们打开 Chrome 的开发者工具,选中 Profile 面板,然后导入我们的快照。

我们现在可以清晰的看见罪魁祸首是 leakyfunc():
堆快照
同时,我们页可以比较两个快照。这样更容易在两个时间点上找到内存泄露:
内存泄露快照比较

[译]你应该知道的5个 Flexbox 技巧

发表于 2016-05-24   |   分类于 css3   |  

header-img

Flexbox 是一个高效的CSS UI设计标准。使用简单的几个 flexbox 属性我们就可以构建我们的页面通过一个一个小的布局快,我们可以对这些布局快可以轻松地进行定位和缩放。

在这篇文章中,我们将要通过5种flexbox的方式来解决普通的css布局问题。其中还包含了这些技术在真实生活中的实践。

创建一个等高的列

如果让你把所有的列的高度弄上去一样高,这是恨烦的。简单的通过 min-height 是不行的,因为一旦内容发生变化,那么一些列会变高而其它的仍然还是原来的高度。

用 flexbox 来解决这个问题再简单不过了,因为痛过这种方式创建的列默认情况下就是等高的。我们要做的就是初始化这个 flex 盒子,然后确保 flex-direction 和 align-items 属性被赋值为默认值。

CSS 部分:

1
2
3
4
5
6
7
8
.container {
/* Initialize the flex model */
display: flex;

/* These are the default values but you can set them anyway */
flex-direction: row; /* Items inside the container will be positioned horizontally */
align-items: stretch; /* Items inside the container will take up it's entire height */
}

HTML 部分:

1
2
3
4
5
6
7
8
9
<div class="container">

<!-- Equal height columns -->

<div>...</div>
<div>...</div>
<div>...</div>

</div>

你可以在 Easiest Way To Create Equal Height Sidebars 这篇文章中查看实例,它创建了一个包含侧边栏和主内容区的响应式页面。
等高的列实例

重新定位元素

以前,如果我们要动态的的区改变元素的顺序,我们可能会尝试一些CSS hack,而且还有写一些 javascript,真是让人沮丧!但是有了 flexbox,只有一个CSS属性就可以搞定这个问题了!

它叫做 order ,就像这个名字一样,一切尽可能的简单。它让我们可以通过一个数字来设定这个flex项在屏幕中的出现顺序(越小的数代表越高的优先级)。

CSS 部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.container{
display: flex;
}

/* Reverse the order of elements */

.blue{
order: 3;
}

.red{
order: 2;
}

.green{
order: 1;
}

HTML 部分:

1
2
3
4
5
6
7
8
9
<div class="container">

<!-- These items will appear in reverse order -->

<div class="blue">...</div>
<div class="red">...</div>
<div class="green">...</div>

</div>

这个属性有非常多多实战应用。如果你想了解的话,你可以看 这篇文章, 它讲了如果使用这个玩意来做一个响应式的评论区。
order 属性

水平垂直居中

在CSS中垂直居中问题我们经常遇到,为什么一个简单的垂直居中实现起来如此复杂?如果 Google 一下 CSS 垂直居中,可以找到无限多的解决方案,它们中的很大一部分都是采用 table 或者 transform 来实现(然而这些东西设计出来不是为来布局的)。

Flexbox 非常简单的解决了这个问题。没有个flex布局都具有两个方向(X轴和Y轴)和两个用来置顶它们都对齐方式的属性。把两个属性都设成居中对齐,我们就可以把这个元素放在它都父级容器的中间了。

CSS 部分:

1
2
3
4
5
6
7
8
9
.container{
display: flex;

/* Center according to the main axis */
justify-content: center;

/* Center according to the secondary axis */
align-items: center;
}

HTML 部分:

1
2
3
4
5
6
7
8
<div class="container">

<!-- Any element placed here will be centered
both horizonally and vertically -->

<div>...</div>

</div>

你可以阅读这篇文章来了解更多
Horizontal And Vertical Centering With Flexbox

创建一个完全的响应式网格

许多的开发者创建响应式网格的时候都依赖一个CSS框架。Bootstrap 是最流行的一个,当然还有其它成百上千个库可以帮你做到。它们都可以正常的工作并且有很多的选项,但是它们都太重了。如果你只是想要实现一个网格布局,仅仅需要 flexbox 就可以帮你搞定了!

在 flexbox 网格系统中,被设置了 display:flex 属性的元素就相当于“行(row)”。它里面的水平方向的列可以是任意数量的元素,可以通过 flex 属性来设置尺寸。flex 模型适应视口的大小,所以这个设置应该在所有的设备上看起来都是可以的。然而,如果我们发现在水平方向上没有足够的空间时,我们可以简单的通过媒体查询来现实一个垂直方向上的布局。

CSS 部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.container{
display: flex;
}

/* Classes for each column size. */

.col-1{
flex: 1;
}

.col-2{
flex: 2;
}

@media (max-width: 800px){
.container{
/* Turn the horizontal layout into a vertical one. */
flex-direction: column;
}
}

HTML 部分:

1
2
3
4
5
6
7
8
9
10
11
12
<div class="container">

<!-- This column will be 25% wide -->
<div class="col-1">...</div>

<!-- This column will be 50% wide -->
<div class="col-2">...</div>

<!-- This column will be 25% wide -->
<div class="col-1">...</div>

</div>

你可以在 The Easiest Way To Make Responsive Headers 查看这项技术的运用。
Responsive Header With Flexbox

创建一个完美的紧贴页面底部的页脚

Flexbox 同样也可以很容易的解决这个问题。通过 flex 元素可以保证页脚永远在页面的底部。

给 body 标签加一个 diplay:flex 属性,这样我们就可以对整个页面使用flex模型属性。这样我们就可以把主要的内容区和页脚区分别作为 flex项,以便于我们准确的控制他们的位置。

CSS 部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
html{
height: 100%;
}

body{
display: flex;
flex-direction: column;
height: 100%;
}

.main{
/* The main section will take up all the available free space
on the page that is not taken up by the footer. */
flex: 1 0 auto;
}

footer{
/* The footer will take up as much vertical space as it needs and not a pixel more. */
flex: 0 0 auto;
}

HTML 部分:

1
2
3
4
5
6
7
8
9
10
11
12
<body>

<!-- All the page content goes here -->

<div class="main">...</div>


<!-- Our sticky foooter -->

<footer>...</footer>

</body>

如果你要了解更多,你可以阅读 The Best Way To Make Sticky Footers。
Sticky Footers With Flexbox

结论

主流的浏览器(不包括 IE9)现在都支持 flexbox 布局模型了,所以,除非你的用户更喜欢用古老的IE浏览器,你是可以非常放心的在产品用用 flexbox 布局的!

我希望这些能够帮助你创建更加强健响应式布局!

原文地址:http://tutorialzine.com/2016/04/5-flexbox-techniques-you-need-to-know-about/

简单介绍 CSS Variables

发表于 2016-03-09   |   分类于 css   |  

css3

如果我们用过动态样式语言(像 Less、 Sass )的话,肯定对其中可以定义变量的特性非常喜欢,特别是随着样式文件越来越复杂的时候,把一些值抽成变量会使代码更好维护。现在随着 CSS 的发展,目前 CSS Variables 也引入了自己的变量,本文就对 CSS Variables 进行简单的介绍。

如何定义和使用 CSS Variables

按照 CSS Variables 规范,我们通过 --* 的方式来创建一个CSS变量,并通过 var(--foo) 的方式来引用一个变量(大小写敏感哦)。例如:

1
2
3
4
5
6
7
:root {
--brand-primary: #338800;
}

body {
background-color: var(--brand-primary);
}

CSS变量同样是可嵌套使用的,:root用来定义全局变量

浏览器兼容性

我在写这篇文章的时候,这个特性依然处于实验阶段,所以,目前来说,只有 FireFox 34+ 、 Chrome 49+ 以及 Safari 9.1+ 支持了这个特性。另外, Chrome 48 其实也支持了这个特性,用户需要在浏览器地址栏输入 chrome://flag/ 找到“Enable experimental Web Platform”选项开启才行。
css variables 兼容性

还有一些你该知道的

  • var() 还可以接受第二个参数( color: var(--header-color, blue); ),表示备选参数,第一个参数获取失败的时候,它就生效了。
  • 变量也是可用嵌套的:

    1
    2
    --base-color: #f93ce9;
    --background-gradient: linear-gradient(to top, var(--base-color), #444);
  • 变量还可以更另一个CSS特性——calc()方法一起使用:

    1
    2
    --container-width: 1000px;
    max-width: calc(var(--container-width) / 2);

推荐阅读

  • 如何提升 CSS 选择器性能

「译」高效的 “box-shadow” 动画

发表于 2015-11-27   |   分类于 css3   |  

原文地址:http://tobiasahlin.com/blog/how-to-animate-box-shadow/

如何才能防止在给 box-shadow 制作动画过渡时导致的每一帧都要进行的重绘(re-paint),从而提高页面的性能?
答案就是:不可能。给变化的 box-shadow 制作动画会大大缩减页面渲染的性能。

但是,这里依然有类似的方法实现相同的效果。尽量的减少重绘的次数,可以保证你的动画能够保证在 60 FPS 左右:通过改变子元素的 opacity 透明度。

Demo

box-shadow 动画对比

查看这个Demo,比较一下两种实现方式的不同。左边的动画是在 box-shadow 的 :hover 状态时执行 box-shadow 动画, 而右边的实现方式中,我们通过 :after 添加了一个伪元素,并给它添加了 box-shadow, 然后通过执行 opacity 动画来是实现相同的效果。

如果你打开你的调试工具,可以看到下面类似的结果(绿色部分表示绘制;越少越好):
timeline 对比

很明显如果我们直接执行 box-shadow 的动画会导致更多的重绘。

为什么会有这样的结果? 只有很少的属性 才能避免在动画的过程不断的重绘,像 opacity 和 transform。
这就是两种方式的不同之处,下面是核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* The slow way */
.make-it-slow {
box-shadow: 0 1px 2px rgba(0,0,0,0.15);
transition: box-shadow 0.3s ease-in-out:
}

/* Transition to a bigger shadow on hover */
.make-it-slow:hover {
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}

/* The fast way */
.make-it-fast {
box-shadow: 0 1px 2px rgba(0,0,0,0.15);
}

/* Pre-render the bigger shadow, but hide it */
.make-it-fast:after {
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
opacity: 0;
transition: opacity 0.3s ease-in-out:
}

/* Transition to showing the bigger shadow on hover */
.make-it-fast:hover:after {
opacity: 1;
}

在上面的例子中,高效的实现方式有两层:一层负责呈现盒子,一层负责盒子阴影的过度动画,只对阴影的 opcity 执行动画。

推荐阅读

  • CSS3 Animate or JS Animate ?

React 编程风格指南

发表于 2015-10-23   |   分类于 javascript , react   |  

本文讨论的是 React.js 编程中的一些编程风格,团队开发中遵循统一的风格有利于提高代码的阅读体验。
本文译自React style guide。下面将从三个方面来讲。

语法

方法顺序遵循生命周期放在前面, render() 方法放在最后

在 react 组件内部,方法的顺序如下:

  1. 生命周期方法(按照时间先后顺序依次为: getDefaultProps, getInitialState, componentWillMount, componentDidMount, componentWillReceiveProps, shouldComponentUpdate, componentWillUpdate, componentDidUpdate, componentWillUnmount )
  2. 其他的方法
  3. render 方法

事件处理函数的命名

采用 “handle” + “EventName” 的方式来命名
Example:

1
<Component onClick={this.handleClick} onLaunchMissiles={this.handleLaunchMissiles} />

事件函数作为属性时的命名

为了跟 react 的事件命名保持一致: onClick, onDrag, onChange, 等等,采用如下格式:

1
<Component onLaunchMissiles={this.handleLaunchMissiles} />

元素跟 return 放在同一行

为了节约空间,采用下面的写法:

1
2
3
return <div>
...
</div>;

而不是:

1
2
3
4
5
return (      // "div" 与 "return" 不在同一行
<div>
...
</div>
);

对HTML的属性进行对齐和排序

如果属性不是太多,那就放在同一行,否则就把每一个属性都单独写一行:

1
2
3
4
5
6
7
8
9
<div className="highlight" key="highlight-div">
<div
className="highlight"
key="highlight-div"
>
<Image
className="highlight"
key="highlight-div"
/>

而不是:

1
2
3
4
5
6
7
8
9
10
<div className="highlight"      // 属性没有在单独行
key="highlight-div"
>
<div // 闭合便签不在单独的行
className="highlight"
key="highlight-div">
<div // 属性没有排序(一般重要的属性写在前面)
key="highlight-div"
className="highlight"
>

一个文件只导出一个 react 类

每一个 .jsx 应该只能导出单独的 react 类。这样有利于测试,因为这些测试框架要求一个文件导出的就是一个函数。
注意:你依然可以在一个文件中定义多个类,只要保证导出的只有一个即可。

语言特色

确保“呈现型”的组件功能单一

把 react 组件 分为“逻辑型组件”和“呈现型组件” 是很有必要的。前者包含的是业务逻辑,里面不应该包含HTML;后者一般是可复用的,可以包含HTML。前者可以拥有自己的内部的 state,而后者不应该拥有。

多用 props

如果能用 props 就不要用 state,这一定程度上可以减少应用程序的复杂度。
一般的模式是:创建一个“无状态”的组件(呈现型组件),只负责呈现数据,把包含 state 的“逻辑型组件”做为这些组件的父级组件。 然后把它内部的 state 作为 props传递给下面的呈现型组件。这些逻辑型组件包含了所有的交互逻辑。

使用 propTypes

react 组件 都应该完成 propTypes 验证。每一个 this.props 的属性都应该有一个与之对应的 propTypes。
避免使用这些没有描述意义的 prop-types:

  • React.PropTypes.any
  • React.PropTypes.array
  • React.PropTypes.object

最好使用:

  • React.PropTypes.arrayOf
  • React.PropTypes.objectOf
  • React.PropTypes.instanceOf
  • React.PropTypes.shape

永远不要在DOM中保存 state

不要通过 data- 属性或class类。所有的信息应该都存储在javascript中,或者在React组件中,或者在React store 中,如果使用了类似 Redux 这样的框架的话。

React 库和组件

不要使用 backbone 模型

直接使用 flux action,或者 $.ajax 来代替。

尽量少用 jQuery 就少用

永远也不要用jquery去操作DOM。
尝试避免jquery插件的使用。有必要的话,把jquery插件包装在React组件中。
你可以使用 $.ajax(但是不要用其他方法,像 $.post) 来进行网络通信。

复用组件

你可以从react-components.com获取第三方React组件。

123…6
McBird

McBird

分享自己的学习经历,实用技巧

27 日志
13 分类
25 标签
GitHub 微博 知乎
© 2015 - 2021 McBird
由 Hexo 强力驱动
主题 - NexT.Muse