艾莉亚的猫 Time is limited, To be a better man

引用计数

最近在看《提高c++性能的编程技术》一书,第十二章提到引用计数,要开始学习新知识了~

学习之前先抄录书中一段精彩的言论

于自然界,熵的原理亦可用于软件工程之中–所有实体都会随着时间的消逝而消失。一个软件项目最初可能源起于某个设计清晰、实现简单的小型原型系统。只包含基本功能的原型系统,要使它们满足上市需求,往往都要经历急速扩展的过程。这通常是为了满足客户对于新功能(有时是难解的)的突发性需求以及对原有瑕疵的改进需要。新功能的开发加上旧错误的修补会对原先清晰明了的设计造成重大破坏。随着时间的推移,设计和实现的清晰性也会随着代码维护及频繁的发布周期而不复存在,软件不可避免的变得紊乱不堪,区分软件好坏的唯一标准就是衰退率。


引用计数是对共享的动态内存的一种管理方法,STL库的string就是用到了引用计数的方法

1. 概念

引用计数用来记录当前有多少指针指向同一块动态分配的内存。当有指针指向这块内存时,计数器加1;当指向此内存的指针销毁时,计数器减1。当引用计数为0时,表示此块内存没有被任何指针指向,此块被共享的动态内存才能被释放。

2. STL库的string利用引用计数共享内存

#include <stdio.h>
#include <string>

using namespace std;

int main()
{
	string str1("aaa");
	printf("the address of str1 is: %x\n",str1.c_str());
	string str2("bbb");
	printf("the address of str2 is: %x\n",str2.c_str());
	string str3("aaa");
	printf("the address of str3 is: %x\n",str3.c_str());
	string str4 = str1;
	printf("the address of str4 is: %x\n",str4.c_str());
	str1 = str2;
	printf("the address of str1 is: %x\n",str1.c_str());
	str2[2] = 'a';
	printf("the address of str2 is: %x\n",str2.c_str());
}

结果如下:

the address of str1 is: 1816028

the address of str2 is: 1816058

the address of str3 is: 1816088 //str3和str1并不共享一块内存

the address of str4 is: 1816028 //str4和str1共享一块内存,所以初始化(string(const char*))和赋值(operator=(const string&))是不一样的

the address of str1 is: 1816058 //str1和str2共享一块内存

the address of str2 is: 18160b8 //写str2,因为引用计数的关系,要分配新的内存给str2

STL string共享内存的原则(copy on write):

利用初始化或赋值生成多个内容相同的string,当没有对这些string进行写操作时,它们会共享同一块内存。当有写操作出现时,才会有新的内存重新分配。

3. 利用引用计数实现简易String

问题:我们对String类的内存进行计数,但引用计数这个变量是类的什么类型的成员变量?

解答:

1) 普通私有成员变量,每个类都有一个独立的计数器变量,在新的类对象拷贝构造和赋值的时候需要进入原来的类对象中去获取这个计数器,再进行修改,在同一个类对象之间缺乏通用性。

2) static变量,类的所有对象公用一个计数器变量。字符串”aaaa”和”bbbb”使用不同的内存,它们应该分别有对应自己内存的计数器变量。

结论,对每一块内存分配一个变量,可以在动态分配字符串内存是多分配一个字节,将计数器的值放在第一个字节中;也可以在动态分配内存前先动态分配一个int型的内存来存放这个计数器。


在《More Effective C++》的Item 29中有关于引用计数的实现,可供参考

2014年阅读书单

深入理解计算机系统

数码单反摄影轻松入门

写给大家看的PPT设计书

计算机算法设计与分析

啊哈!算法

深入理解C指针

C语言接口与实现

你必须知道的495个C语言问题

提高C++性能的编程技术

Essential C++中文版

黄金时代

沉默的大多数

学习vi和Vim编辑器

Berkeley DB

Berkeley DB的简介


Berkeley DB(BDB)是一个高性能的嵌入式数据库编程库(引擎),它可以用来保存任意类型的键/值对 (Key/Value Pair),而且可以为一个键保存多个数据。Berkeley DB可以支持数千的并发线程同时操作数据库,支持最大256TB的数据。

BDB提供诸如C语言,C++,Java,Perl,Python,Tcl等多种编程语言的API,并且广泛支持大多数类Unix操作系统和Windows操作系统以及实时操作系统(如 VxWorks)。

1991年,Berkeley DB的第一个版发行(Linux系统也在这一年诞生),其最初的开发目的是以新的HASH访问算法来代替旧的hsearch函数和大量的dbm实现,该版本还包含了B+树数据访问算法。

1992年,BSD UNIX第4.4发行版中包含了Berkeley DB1.85版。基本上认为这是Berkeley DB的第一个正式版。

1996年,Sleepycat软件公司成立,提供对Berkeley DB的商业支持。

2006年,Sleepycat被Oracle收购,当时最新版本是4.7.25。

2009年,SUN被Oracle收购,不知道MySQL会不会再次启用Berkeley DB。

Berkeley DB的特点


Berkeley DB可以轻松支持上千个线程同时访问数据库,支持多进程、事务等特性。Berkeley DB运行在大多数的操作系统中,例如大多数的UNIX系统, 和windows系统,以及实时操作系统。 Berkeley DB 还拥有对一些老的UNIX数据库,例如dbm, ndbm und hsearch的兼容接口, 对于在java系统中的使用,Berkeley DB提供了一个压缩成jar单个文件的java版本。 这个版本可以运行在java虚拟机上使用,并且拥有和C语言版本相同的所有操作和功能。 Berkeley DB XML,是一个接口,通过它可以实现对XML数据存贮的支持。对XML数据的访问,会使用相应的查询语句如Xquery, Xpath。 Berkeley DB只支持单一的数据结构,它的所有数据包括两个部分:key 和 data. Berkeley DB原则上是为嵌入式数据库设计的。

喵喵之歌

蓝色寂静的夜里

我一个人思考哲学

虫儿在草丛中 打滚 鸣叫

叫得很可口的样子

今夜 我不会吃他们的

月亮那么的…圆呀

那么的圆 那么圆

那么的…

比世界任何圆的东西都要圆

比世界任何圆的东西都要圆

广大的广大的 宇宙的某处

还有另一个我吧

和我一样的在草丛中

在弹着吉他吗?

在唱着喵喵的歌吗?

孤独一人是这么的 寂寞啊

这么的 寂寞 这么的…

这个时候大家在做什么呢喵

这个时候大家在做什么呢喵

变得想打电话给其他人了喵

Awk、Sed、Find工具的使用

最近在写shell脚本,主要工作就是解析配置文件,那么学习sed与awk就在所难免了,另外还系统的看了find命令的使用,现在就将这些成果汇总起来,以便今后参考。

Awk命令

awk 是一种编程语言,对文本和数据进行处理,支持正则表达式,突出特点是对文本列的操作。

1 常见操作

awk ‘{print $1,$3}’ tmp.txt

awk –F ‘:’ ‘{print $1”|”$3}’ tmp.txt  //以冒号作为域分割符并且输出的分割符为|

2 打印记录

awk ‘BEGIN {print “Begin   \n-----------------”}

{print $0}’ tmp.txt //打印头

awk ‘BEGIN {print “Begin   \n-----------------”}

{print $0}

END {print” -----------------\nEnd”}’ tmp.txt    //打印头尾

3 条件运算符

awk ‘{if ($1~/tomy/) print $0}’ tmp.txt //匹配文本域1为tomy的记录

awk ‘$2==”30” {print $1,”age is 30.”}’ tmp.txt   //精确匹配

4 利用正则表达式

awk ‘/[Gg]reen/’ tmp.txt    //匹配Green或者green

awk ‘$4~/[Gg]reen/’ tmp.txt

awk ‘$4~/([Gg]reen|[Rr]ed)/’ tmp.txt    //或关系匹配

5 使用内置变量

awk ‘{print NF,NR,$0}

END {print FILENAME}’ tmp.txt //NF为列数,NR为行号

6 使用内置字符串函数

awk ‘gsub (/30/,thirty) {print $0}’ tmp.txt    //把有30的行中的30改为thirty

awk ‘BEGIN {print split(“123#456#789”,m_array,”#”)}’  //split返回数组m_array的下标数3,m_array取值:m_array[1]为123,m_array[2]为456,m_array[3]为789

7 输出函数printf

awk ‘{printf “%-10s---%s\n”,$1,$3}’ tmp.txt      //类似C语言printf函数

Sed命令

sed是非交互文本流编辑器,使用sed可以从文件和字符串中抽取所需信息。

1 打印范围

sed –n ‘1,3p’ sed.txt > sed.tmp

sed –n ‘1,$p’ sed.txt > sed.tmp

2 模式查询

sed –n ‘/should/p’ sed.txt //查找should的行

sed –n ‘/should/=’ sed.txt //输出匹配的行号

3 特殊字符查询

sed –n ‘/\./’p sed.txt        //查找有.的行

4 删除文本

sed ‘1,3d’ sed.txt

sed ‘/should/d’ sed.txt

5 替换文本

sed ‘s/PS/ps/’ sed.txt       //替换每行第一个匹配

sed ‘s/PS/ps/g’ sed.txt           //全文替换

sed ‘1,3 s/should/SHOULD/g’ sed.txt         //指定范围替换

sed ‘1 s/should/SHOULD/g’ sed.txt      //指定行替换

6 sed脚本文件

6.1 含sed命令的脚本
  $ cat append.sed

  #!/bin/sed –f

  /should/ a\

	Just a test.

	$ chmod +x append.sed

	$ ./append.sed sed.txt
6.2 不含sed命令脚本
	$ cat append.sed

	/should/ a\

	Just a test.

	$ chmod +x append.sed

	$ sed -f append.sed sed.txt

Find命令

1 name选项

find ~ -name “*.txt” –print

find . –name “[A-Z]*” –print

2 perm选项

find . –perm 755 -print

3 按更改时间查找

find / -mtime -5 –print     //更改时间在五日以内

find / -mtime +3 –print    //更改时间在三日之前

4 type选项

find /etc –type d –print    //查找/etc目录下所有的目录

find /etc –type l –print     //查找/etc目录下所有的符号链接文件

5 使用exec或ok

find . –type f –exec ls –l {} \; //注意{}和\;之间有空格

find . -name “*.log” –mtime +5 -exec rm {} \;