《王阳明度阴山》--读后感

在高中开始学习哲学的时候,就知道哲学有两大阵营,唯物主义和唯心主义。唯物主义认为世界的本源是物质,物质是客观存在的,物质决定意识,中国古代代表的是朱熹的格物致知。唯心主义认为世界的本质是意识,心外无物,像佛学,道教和王阳明的心学都是唯心主义的代表。

在《度阴山》这本书上,说了一个很有趣的例子 :

王阳明游南镇,一友指岩中花树问曰:“天下无心外之物,如此花树在深山中自开自落,于我心亦何相关?”先生曰:“你未看此花时,此花与汝心同归于寂;你来看此花时,则此花颜色一时明白起来;便知此花不在你的心外。”

翻译过来就是: 王阳明于朋友游南镇,看到岩石上面友一朵花,他的朋友指着岩石花说:“你常说心外无物,这个花在这个深山中花开花落,和我的心有什么关心呢?” 王阳明说:“你没有看到这个花的时候,这个花与你的心一同沉寂,当你看到此花时,花的颜色在你的心中明白了起来,看来这个花并没有在你的心外。”

王阳明朋友的理解是唯物主义的角度去理解,我想大多数人也都会认为第一种说法更为合理,因为花确实是客观存在,不受任何人的影响,即使你人的意识没了,花依然存在,所以是先有了花,才能谈生出人们对花的意识。

从王阳明的心学角度考虑,当你看到花的时候,花的颜色,花的形状,”花”的这个名字,都已经在你的心中了,只不过在你看到的那个时刻,产生了一个碰撞,在你看到花之前就已经有了花的意识,从反面角度来说,如果一个人失去了意识,就不可能感受到物质的存在,如果所有的人和生物都失去了意识,那么整个宇宙就没有了意义。

对于上面的两种结识,我更喜欢王阳明的心学,这个也是我写这篇博客的目的。唯物主义固然是对的,也是现代科学的基础,但唯物主义只能教会我们更好认识世界,确没有告诉我们认识自己,而再完美的科学也不能脱离人的意识而存在。而王阳明的心学追求的是”知行合一”,认为我们的良知无所不能,良知能做到一切,让我们跟随自己的良知去做事,良知认为什么是对的就做什么,不对的就想办法把他克服掉。

有人会问,王阳明的心学和佛学有很多类似的地方,都认为心外无物,这个书中也给了我们的答案,心学于佛学最大的不同是佛学是灭了人的七情六欲,所以心经里面就有照见五蕴皆空等等的句子。心学认为人的七情六欲是正常的,我们只要管理好他就行了。虽然说起来很简单,这个正是心学高明的地方。

奉唯物观点为经典,存天理去人欲,人生在宇宙,犹如沧海一粟,生命的脆弱带来的只是意志的脆弱和人性的虚伪,所以我们不仅需要唯物观点认识世界,也需要心学来充实内心,社会的浮躁,恰恰是只在乎了前者,而忽略缺乏了内心的修养。

AMD的规范演化

对于web项目来说,打交道的不仅仅有后台,前台页面也是少不了的,而前台的页面js也常常是我们后台程序员必须要使用的语言, 今天说下项目中的js的组织方式。

文件函数型

所谓文件函数型是指所有的js的脚本都是中都是一个一个的方法,没有任何的封装,这也是传统的项目中常用的方法。如下:

file1.js

1
2
3
4
function add(a,b){
return a+b;
}

file2.js

1
2
3
4
function minutes(a,b){
return a-b;
}

当我们想使用个方法的时候只需要应用相应的js就行了,这样的缺点很明显,就是要时刻明确文件之间的相互依赖关系的顺序,不然就会导致程序无法正常的运行。 比如还是上面的两个js,我在file1.js中有家一段代码:

file1.js

1
2
3
4
5
6
7
8
function add(a,b){
return a+b;
}

function sum(a,b,c){
return add(a,minutes(b,c));
}

如果在引用的时候,先引用的file1.js则会导致files1.js中有方法没有找到。 如果项目足够的大,就纯粹的js的依赖关系就足以让我们焦头烂额。

这种方法还有很多潜在的风险,如果我在file1.js中有定义了一个minutes方法,这样file2.js中的方法就面临被覆盖的风险,所以这种布局的方式,不应该是项目的首选。

jquery扩展型

在web的项目中,在面对dom操作的时候,传统的js的过于繁杂,所以jquery的使用应该占了很大的一部分的比重(确切的说在MVVM框架流行前)。

jquery也提供了两种扩展方法:   

  • 静态方法扩展    

    jquery静态方法的扩展是直接扩展到$对象上面 :

1
2
3
$.funcA=function(){
// do something
}

在任何引入jquery的地方都可以使用$.funcA()来调用

  • jquery对象方法扩展
1
2
3
4
$.fn.funcB=function(){
//do something
}

使用的方法: $(“#id”).funcB()来调用。

上面的方面解决了方法见的相互的依赖顺序问题,但没有解决方法被覆盖的问题,同时又带来了一个副作用,增加了js方法的调用深度,降低了js的执行效率。

模块加载型

模块话加载是对jquery扩展和文件方法的一个进化,把每个方法都用一个模块封装起来,不至于被外面的方法覆盖。

module1.js

1
2
3
4
5
6
7
8
var module1=function(){

return {
add:function(a,b){
return a+b;
}
}
}();

module2.js

1
2
3
4
5
6
7
var module2=function(){
return {
minutes:function(a,b){
return a-b;
}
}
} ();

如果想使用add方法可以直接引用module1.js,调用module1.add方法。

上面的方法解决的方法被覆盖的问题,但没有解决模块化依赖的问题,这个问题的解决就要靠我们下面要说的AMD的规范。

AMD模块开发规范

上面模块话的开发虽然解决的js的方法的覆盖问题,但js依赖的问题仍然存在,解决这个问题的终极方案就是AMD规范。

AMD规范就是其中比较著名一个,全称是Asynchronous Module Definition,即异步模块加载机制。从它的规范描述页面看,AMD很短也很简单,但它却完整描述了模块的定义,依赖关系,引用关系以及加载机制。

这里用requirjs来解释说明AMD加载的原理:

定义模块:

1
2
3
4
5
6
7
8
9
define(['math', 'graph'], 
function ( math, graph ) {
return {
plot: function(x, y){
return graph.drawPie(math.randomGrid(x,y));
}
}
};
);

上面代码 依赖math和graph两个库,在定义模块前声明了依赖。

引用模块:

1
2
3
require(['foo', 'bar'], function ( foo, bar ) {
foo.doSomething();
});

更多内容参见:
阮一峰-requireJS和AMD规范

vim的使用入门

一直都想写关于vim的使用教程,因为在很多的场景下不得不去使用vim去编辑文本,今天有时间就相关的常用的命令整理下(本文只适合入门的读者,想获得高级教程请止步) ,工具只要经常的使用自然就能熟能生巧。

vim概述

vim是linu下面常用的文本编辑工具,可以使用 vim -v 来查看有没有安装,如果没有安装可以使用 以下命令安装:

sudo apt-get install vim        

vim 有两种模式,命令模式和插入模式。从字面的意思很容易理解两者的用的情景:

  • 命令模式:在这个情况下每一个字符都是一个命令 ,如果想转换成插入模式直接输入插入命令即可(a,A,i,I等)

  • 插入模式:可以正常的输入文本,使用esc可以切换成命令模式

vim 使用


打开、新建、保存、退出


  • 打开和新建文件
vim 1.txt      //如果1.txt存在直接打开,如果不存在直接新建

上面的命令是在命令行中直接使用的,如果我们已经打开了一个文件,又想再打开文件:

:e 1.txt      

如果想打开多个文件,可以直接在后面跟上多个文件名,用空格隔开.

vim 1.txt  2.txt
  • 保存和退出
    命令 Demo 相关功能
    :w :w 保存
    :w fileName :w save.txt 另存为
    :wq或者ZZ :wq或者ZZ 保存并退出
    :q! :q! 不修改直接退出
    :wq! :wq! 保存并退出(root用户才能使用)

插入、删除、跳转


命令 Demo 相关功能
a a 在光标所在位置后插入
A A 在光标所在行尾插入
i i 在光标所在字符前插入
I I 在光标所在字符行首插入
o o 在光标下插入
O O 在光标下插入
x x 删除光标所在处字符
hjkl hjkl 移动光标
gg gg 跳转到第一行
G G 到最后一行
nG或:n nG或:n 到第n行
$ $ 移动到行首
0 0 移动到行尾
------------------------------------- #### 选择、 拷贝、粘贴、剪切 -------------------------------------  
命令 Demo 相关功能
v v 字符选择
V V 选择一行
ctrl+v ctrl+v 矩形选择
y y 复制选中
yy yy 复制一整行
nyy 2yy 复制前n行
p p 在光标下面粘贴
P P 在光标上面粘贴
d d 剪切选中
dd dd 剪切一整行,可以用来删除
------------------------------------- #### 搜索、替换 -------------------------------------
命令 Demo 相关功能
/string /abc 搜索字符串 ,使用n可以跳转到下一个匹配
:set ic :set ic 字符搜索不区分大小写
:set noic :set noic 字符搜索区分大小写
%s/old/new/g或者%s/abc/abc/c %s/abc/ABC/g || %s/abc/ABC/c 全文文本替换 /g不询问直接替换 /c询问是否替换
n,m/old/new/g或者n,m/abc/abc/c n,m/abc/ABC/g || n,m/abc/ABC/c 指定行号文本替换 /g不询问直接替换 /c询问是否替换

翻页


整页翻页 ctrl-f ctrl-b

f就是forword b就是backward

翻半页: ctrl-d ctlr-u
d=down u=up

滚一行: ctrl-e ctrl-y

zz 让光标所杂的行居屏幕中央
zt 让光标所杂的行居屏幕最上一行 t=top
zb 让光标所杂的行居屏幕最下一行 b=bottom


全选


ggVG
稍微解释一下上面的命令

gg 让光标移到首行,在vim才有效,vi中无效
V 是进入Visual(可视)模式
G 光标移到最后一行

服务器CPU居高不下--解决问题历程

基本的概述

在一个服务器的集群上面,服务器的CPU长时间居高不下,响应的时间也一直很慢,即使扩容了服务器CPU的下降效果也不是很明显。

对于CPU过高的原因,可以总结到以下原因:

  • 太多的循环或者死循环

  • 加载了过多的数据,导致产生了很多的大对象

  • 产生了过多的对象,GC回收过于频繁(如:字符串拼接)

对于上面的情况,难点不是优化代码,难点在于定位到问题的所在,下面我们就用Dump抓包的方式来定位到问题的所在。介绍这个内容之前,我们要先回顾下.Net中垃圾回收的基础知识和一个工具的准备。


基础知识


垃圾回收触发条件

  • 代码显示调用System.GC的静态方法

  • windows报告低内存情况

  • CLR正在卸载AppDoamin

  • CLR正在关闭

大对象垃圾回收

CLR将对象分为大对象和小对象,认为大于85000字节或者更大的字节是大对象,CLR用不同的方式来对待大对象和小对象:

  • 大对象不是在小对象的地址空间分配,而是在进程地址空间和其他地方分配

  • GC不会压缩大对象,在内存中移动他们的代价过高,但这样会造成地址空间的碎片化,以至于会抛出OutOfMemeryException 异常。

  • 大对象总是在第二代回收。

工具准备

  1. 下载[windbg文件](dbg_amd64_6.12.2.633.msi)

  2. 相关DLL准备clr.dll和sos.dll,(都在对应.Net版本安装目录下面,我的安装目录在C:\Windows\Microsoft.NET\Framework64\v4.0.30319)

  3. 一个cpu运行的较高的时期的DUMP文件(下面会说如何获取)

  4. 准备测试代码,此处为了演示方便,简单了写了一个有潜在问题的代码:

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
public  class Common
{
public static List<string> GetList()
{
var list=new List<string>();
for (int i = 0; i < 10000; i++)
{
list.Add(i.ToString());
}
return list;
}


public static string GetString(List<string> list)
{
var str = "";
foreach (var l in list)
{
str += string.Format("'{0}',", l);
}
if (str.Length > 0)
{
str.Remove(str.Length - 1);
}
return str;
}
}

我们知道在字符串的拼接的时候,每一个字符串都是一个对象,拼接后又产生了一个新对象,所以在GetString这个方法中会有大量的GC操作,下面我们就调用下这个代码,看下CPU的情况,为了模拟并发情况,我们开多个标签,每个标签每1s秒中刷新一次。

CPU

抓取Dump

在任务管理器中选择应用程序池对应的w3wp.exe,右击–>创建转储文件。创建完成后,会提示出指定的路径

taskManger

taskManger

根据上面的步骤,我们准备我们分析的文件如下:

dumpfile

分析Dump

  • 打开windbg,加载对应的dump文件

    dumpOpen
    dumpOpen

  • 配置Sysmbol,添加”cachec:\mysymbol;srvhttp://msdl.microsoft.com/download/symbols
    dumpOpen
    dumpOpen

  • load sos.dll和clr.dll,命令如下:

    .load D:\windbg\sos.dll 
    .load D:\windbg\clr.dll
    
  • 运行命令!threadpool 显示有关托管线程池的信息,其它一些SOS 调试扩展命令.

    dumpOpen

  • 运行!runaway 查询cpu占用时长比较长的几个线程Id

    dumpOpen

  • 运行~22s (进入线程查看),kb(查看对应的调用)

    dumpOpen

  • 运行~* kb 查看所有线程的堆栈调用

    dumpOpen

  • 在上面搜索GC和大对象出现的线程 (ctrl+f搜索:GarbageCollectGeneration和allocate_large_object )

    dumpOpen

  • 可以看到定位触发GC的线程是31号线程

  • 运行命令~31s 进入31线程,再运行!clrstack查看堆栈调用,最终可以定位到出问题的代码,是由于字符串的拼接导致大量的对象产生,从而触发了GC。

    dumpOpen

Java反射和注解

反射

反射是指在运行的状态,对于任意一个类,都能够知道类里面的所有的属性和方法,并能够进行属性的赋值和方法的调用 。 在Java中使用Java.lang下面的Class来表示**类型的”类” ** ,在JDK中定义接口如下

阅读更多

如何使用正则表达式

说到正则,可能很多人会很头疼这个东西,除了计算机好像很难快速的读懂这个东西,更不用说如果使用了。下面我们由浅入深来探索下正则表达式:

ps:此文适用于还有没有入门正则表达基础的读者

阅读更多

字符编码探密--ASCII,UTF8,GBK,Unicode

目录

ASCII 的由来

在计算机的“原始社会”,有人想把日常的使用的语言使用计算机来表示, 我们知道在计算机的世界里面,只有0和1,为了解决尽量多的去表示字符,最终他们决定用8位0和1(一个字节)来表示字符,并且规定当机器读到这几个数据的时候,做出动作或者打印出指定的字符:

阅读更多

多线程如何排队执行

场景

有一个这样场景,程序会有一个非常耗时的操作,但要求耗时的操作完成后,再顺序的执行一个不耗时的操作,而且这个程序的调用,可能存在同时调用的情况。

阅读更多

docker 入门与安装

Docker的概念

什么是Docker

Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机)、bare metal、OpenStack 集群和其他的基础应用平台。

阅读更多
Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×