🚙

💨 💨 💨

×

  • Categories

  • Archives

  • Tags

  • About

redis概要之数据类型

Posted on 07-11-2015 | In DB

Redis简介要义

  • Redis运行在内存中但是可以持久化到磁盘, 重启的时候可以再次加载进行使用

  • Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行

  • Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作

  • Redis支持数据的备份,即master-slave模式的数据备份

Redis数据类型

Redis的数据类型很重要, 这是他做很多事情的基础, 不理解的话很难用好

. . .

python和lua数据类型的比较

Posted on 07-11-2015 | In Misc

Python比较特殊的数据类型:

List []

例如 :

#!/usr/bin/python
# -*- coding: UTF-8 -*-

list = [ 'runoob', 786 , 2.23, 'john', 70.2 ]
tinylist = [123, 'john']

print list # 输出完整列表
print list[0] # 输出列表的第一个元素
print list[1:3] # 输出第二个至第三个的元素
print list[2:] # 输出从第三个开始至列表末尾的所有元素
print tinylist * 2 # 输出列表两次
print list + tinylist # 打印组合的列表

以上实例输出结果:

['runoob', 786, 2.23, 'john', 70.2]
runoob
[786, 2.23]
[2.23, 'john', 70.2]
[123, 'john', 123, 'john']
['runoob', 786, 2.23, 'john', 70.2, 123, 'john']

Tuple(元祖)(),相当于只读列表,不可以二次赋值

tuple = ( 'runoob', 786 , 2.23, 'john', 70.2 ), 除了元祖用()而list用[], 而且元祖只是可读的, 其他的跟list一毛一样

dictionary(字典){},key值对

#!/usr/bin/python
# -*- coding: UTF-8 -*-

dict = {}
dict['one'] = "This is one"
dict[2] = "This is two"

tinydict = {'name': 'john','code':6734, 'dept': 'sales'}


print dict['one'] # 输出键为'one' 的值
print dict[2] # 输出键为 2 的值
print tinydict # 输出完整的字典
print tinydict.keys() # 输出所有键
print tinydict.values() # 输出所有值

输出结果为:

This is one
This is two
{'dept': 'sales', 'code': 6734, 'name': 'john'}
['dept', 'code', 'name']
['sales', 6734, 'john']

lua比较特殊的数据类型

lua变量

变量在使用前,必须在代码中进行声明,即创建该变量。

编译程序执行代码之前编译器需要知道如何给语句变量开辟存储区,用于存储变量的值。

Lua 变量有三种类型:全局变量、局部变量、表中的域。

Lua 中的变量全是全局变量,那怕是语句块或是函数里,除非用 local 显式声明为局部变量。

局部变量的作用域为从声明位置开始到所在语句块结束。

变量的默认值均为 nil。

test.lua 文件脚本
a = 5               -- 全局变量
local b = 5 -- 局部变量

function joke()
c = 5 -- 全局变量
local d = 6 -- 局部变量
end

joke()
print(c,d) --> 5 nil

do
local a = 6 -- 局部变量
b = 6 -- 全局变量
print(a,b); --> 6 6
end

print(a,b) --> 5 6

执行以上实例输出结果为:

$ lua test.lua 
5 nil
6 6
5 6

lua的特有的东西table(表)

在 Lua 里,table 的创建是通过”构造表达式”来完成,

最简单构造表达式是{},用来创建一个空表。

也可以在表里添加一些数据,直接初始化表:

-- 创建一个空的 table
local tbl1 = {}

-- 直接初始表
local tbl2 = {"apple", "pear", "orange", "grape"}

Lua 中的表(table)其实是一个”关联数组”(associative arrays),数组的索引可以是数字或者是字符串。

-- table_test.lua 脚本文件
a = {}
a["key"] = "value"
key = 10
a[key] = 22
a[key] = a[key] + 11
for k, v in pairs(a) do
print(k .. " : " .. v)
end

脚本执行结果为:

$ lua table_test.lua 
key : value
10 : 33

不同于其他语言的数组把 0 作为数组的初始索引,在 Lua 里表的默认初始索引一般以 1 开始。

-- table_test2.lua 脚本文件
local tbl = {"apple", "pear", "orange", "grape"}
for key, val in pairs(tbl) do
print("Key", key)
end

脚本执行结果为:

$ lua table_test2.lua 
Key 1
Key 2
Key 3
Key 4

table 不会固定长度大小,有新数据添加时 table 长度会自动增长,没初始的 table 都是 nil。

-- table_test3.lua 脚本文件
a3 = {}
for i = 1, 10 do
a3[i] = i
end
a3["key"] = "val"
print(a3["key"])
print(a3["none"])

脚本执行结果为:

$ lua table_test3.lua 
val
nil

epoll扼要总结

Posted on 06-22-2015 | In Linux

epoll 编程接口

epoll API是Linux系统专有的,在2.6版中新增。

epoll API的核心数据结构称作epoll实例,它和一个打开的文件描述符相关联。这个文件
描述符不是用来做I/O操作的,相反,它是内核数据结构的句柄,这些内核数据结构实现了两
个目的。

  • 记录了在进程中声明过的感兴趣的文件描述符列表-interest list(兴趣列表)。
  • 维护了处于I/O就绪态的文件描述符列表-ready list(就绪列表)。

ready list中的成员是interest list的子集。

对于由epoll检查的每一个文件描述符,我们可以指定一个位掩码来表示我们感兴趣的事
件。这些位掩码同poll()所使用的位掩码有着紧密的关联。

. . .

socket可读可写条件与非阻塞connect或accept浅析

Posted on 06-22-2015 | In NP

socket可读的条件:

  • socket的接收缓冲区中的数据字节大于等于该socket的接收缓冲区低水位标记的当前大小。对这样的socket的读操作将不阻塞并返回一个大于0的值(也就是返回准备好读入的数据)。我们可以用SO_RCVLOWAT这个socket选项来设置该socket的低水位标记。对于TCP和UDP的socket而言,其缺省值为1.
  • 该连接的读这一半关闭(也就是接收了FIN的TCP连接)。对这样的socket的读操作将不阻塞并返回0
  • 给监听套接字准备好新连接
  • 有一个socket有异常错误条件待处理.对于这样的socket的读操作将不会阻塞,并且返回一个错误(-1),errno则设置成明确的错误条件.这些待处理的错误也可通过指定socket选项SO_ERROR调用getsockopt来取得并清除;

. . .

const和volatile和mutable讲解

Posted on 05-24-2015 | In Misc

const关键字

const 是比较常见的关键字, 也是非常好的预防错误的手段.

const 修饰普通变量和指针

const 修饰变量,一般有两种写法:

const TYPE value;

TYPE const value;

这两种写法在本质上是一样的。它的含义是:const 修饰的类型为 TYPE 的变量 value 是不可变的。对于一个非指针的类型 TYPE,无论怎么写,都是一个含义,即 value 值不可变。 例如:

const int nValue;    //nValue 是 const

int const nValue;    //nValue 是 const

. . .

关系型数据库与NoSQL的爱恨情仇

Posted on 05-20-2015 | In DB

NoSQL因关系数据库的不足而生

随着互联网的不断发展,各种类型的应用层出不穷,所以导致在这个云计算的时代,

对技术提出了更多的需求,主要体现在下面这四个方面:

  • 低延迟的读写速度:应用快速地反应能极大地提升用户的满意度;
  • 支撑海量的数据和流量:对于搜索这样大型应用而言,需要利用PB级别的数据和能应对百万级的流量;
  • 大规模集群的管理:系统管理员希望分布式应用能更简单的部署和管理;

庞大运营成本的考量:IT经理们希望在硬件成本、软件成本和人力成本能够有大幅度地降低;

目前世界上主流的存储系统大部分还是采用了关系型数据库,其主要有一下优点:

  • 事务处理—保持数据的一致性;
  • 由于以标准化为前提,数据更新的开销很小(相同的字段基本上只有一处);
  • 可以进行Join等复杂查询。

虽然关系型数据库已经在业界的数据存储方面占据不可动摇的地位,但是由于其天生的几个限制,

使其很难满足上面这几个需求:

  • 扩展困难:由于存在类似Join这样多表查询机制,使得数据库在扩展方面很艰难;
  • 读写慢:这种情况主要发生在数据量达到一定规模时由于关系型数据库的系统逻辑非常复杂,使得其非常容易发生死锁等的并发问题,所以导致其读写速度下滑非常严重;
  • 成本高:企业级数据库的License价格很惊人,并且随着系统的规模,而不断上升;
  • 有限的支撑容量:现有关系型解决方案还无法支撑Google这样海量的数据存储;

业界为了解决上面提到的几个需求,推出了多款新类型的数据库,并且由于它们在设计上和传统的NoSQL数据库相比有很大的不同,
所以被统称为“NoSQL”系列数据库。

总的来说,在设计上,它们非常关注对数据高并发地读写和对海量数据的存储等,与关系型数据库相比,它们在架构和数据模型方量面做了“减法”,

而在扩展和并发等方面做了“加法”。

现在主流的NoSQL数据库有MongoDB和Redis以及BigTable、Hbase、Cassandra、SimpleDB、CouchDB、等。

接下来,将关注NoSQL数据库到底存在哪些优缺点。

NoSQL的优缺点

在优势方面,主要体现在下面这三点:

  • 简单的扩展:典型例子是Cassandra,由于其架构是类似于经典的P2P,所以能通过轻松地添加新的节点来扩展这个集群;
  • 快速的读写:主要例子有redis,由于其逻辑简单,而且纯内存操作,使得其性能非常出色,单节点每秒可以处理超过10万次读写操作;
  • 低廉的成本:这是大多数分布式数据库共有的特点,因为主要都是开源软件,没有昂贵的License成本;

但瑕不掩瑜,NoSQL数据库还存在着很多的不足,常见主要有下面这几个:

  • 不提供对SQL的支持:如果不支持SQL这样的工业标准,将会对用户产生一定的学习和应用迁移成本;
  • 支持的特性不够丰富:现有产品所提供的功能都比较有限,大多数NoSQL数据库都不支持事务,也不像MS SQL Server和Oracle那样能提供各种附加功能,比如BI和报表等;
  • 现有产品的不够成熟:大多数产品都还处于初创期,和关系型数据库几十年的完善不可同日而语;

上面NoSQL产品的优缺点都是些比较共通的,在实际情况下,每个产品都会根据自己所遵从的数据模型和CAP理念而有所不同.

编译过程

Posted on 05-07-2015 | In Misc


通常我们使用gcc来生成可执行程序,命令为:gcc hello.c,默认生成可执行文件a.out



其实编译(包括链接)的命令:gcc hello.c 可分解为如下4个大的步骤:




    • 预处理(Preprocessing)
    • 编译(Compilation)
    • 汇编(Assembly)
    • 链接(Linking)




gcc_compilation


预处理




1.       预处理(Preproceessing)



预处理的过程主要处理包括以下过程:



  • 将所有的#define删除,并且展开所有的宏定义
  • 处理所有的条件预编译指令,比如#if #ifdef #elif #else #endif等
  • 处理#include 预编译指令,将被包含的文件插入到该预编译指令的位置。
  • 删除所有注释 “//”和”/ /”.
  • 添加行号和文件标识,以便编译时产生调试用的行号及编译错误警告行号。
  • 保留所有的#pragma编译器指令,因为编译器需要使用它们


 



通常使用以下命令来进行预处理:



gcc -E hello.c -o hello.i



参数-E表示只进行预处理 或者也可以使用以下指令完成预处理过程



cpp hello.c > hello.i      /  cpp – The C Preprocessor  /



直接cat hello.i 你就可以看到预处理后的代码



 

编译


2.       编译(Compilation)



编译过程就是把预处理完的文件进行一系列的词法分析,语法分析,语义分析及优化后生成相应的汇编代码。



$gcc –S hello.i –o hello.s



或者



$ /usr/lib/gcc/i486-linux-gnu/4.4/cc1 hello.c



注:现在版本的GCC把预处理和编译两个步骤合成一个步骤,用cc1工具来完成。gcc其实是后台程序的一些包装,根据不同参数去调用其他的实际处理程序,比如:预编译编译程序cc1、汇编器as、连接器ld



可以看到编译后的汇编代码(hello.s)如下:

 .file   "hello.c"
.section .rodata
.LC0:
.string "Hello, world."
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl $.LC0, (%esp)
call puts
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits


 

汇编


3.       汇编(Assembly)



汇编器是将汇编代码转变成机器可以执行的命令,每一个汇编语句几乎都对应一条机器指令。汇编相对于编译过程比较简单,根据汇编指令和机器指令的对照表一一翻译即可。



$ gcc –c hello.c –o hello.o



或者



$ as hello.s –o hello.co



由于hello.o的内容为机器码,不能以普通文本形式的查看(vi 打开看到的是乱码)。



 

链接

4.       链接(Linking)



通过调用链接器ld来链接程序运行需要的一大堆目标文件,以及所依赖的其它库文件,最后生成可执行文件。



ld -static crt1.o crti.o crtbeginT.o hello.o -start-group -lgcc -lgcc_eh -lc-end-group crtend.o crtn.o (省略了文件的路径名)。



 

编译器和链接器具体做了什么


helloworld的大体编译和链接过程就是这样了,那么编译器和链接器到底做了什么呢?



 



编译过程可分为6步:

  • 词法分析:扫描器(Scanner)将源代的字符序列分割成一系列的记号(Token)。lex工具可实现词法扫描。
  • 语法分析:语法分析器将记号(Token)产生语法树(Syntax Tree)。yacc工具可实现语法分析(yacc: Yet Another Compiler Compiler)。
  • 语义分析:静态语义(在编译器可以确定的语义)、动态语义(只能在运行期才能确定的语义)。
  • 源代码优化:源代码优化器(Source Code Optimizer),将整个语法书转化为中间代码(Intermediate Code)(中间代码是与目标机器和运行环境无关的)。中间代码使得编译器被分为前端和后端。编译器前端负责产生机器无关的中间代码;编译器后端将中间代码转化为目标机器代码。
  • 目标代码生成:代码生成器(Code Generator).
  • 目标代码优化:目标代码优化器(Target Code Optimizer)。


 



链接的主要内容是把各个模块之间相互引用的部分处理好,使得各个模块之间能够正确地衔接。



链接的主要过程包括:地址和空间分配(Address and Storage Allocation),符号决议(Symbol Resolution),重定位(Relocation)等。

链接分为静态链接和动态链接

  1. 静态链接是指在编译阶段直接把静态库加入到可执行文件中去,这样可执行文件会比较大。

  2. 动态链接则是指链接阶段仅仅只加入一些描述信息,而程序执行时再从系统中把相应动态库加载到内存中去。


静态链接的大致过程如下图所示:

static_linking

关于Valgrind所报的4种内存丢失

Posted on 05-02-2015 | In Misc

官方解释及分析

摘自http://valgrind.org/docs/manual/faq.html#faq.deflost

5.2.With Memcheck’s memory leak detector, what’s the difference between “definitely lost”, “indirectly lost”, “possibly lost”, “still reachable”, and “suppressed”?

The details are in the Memcheck section of the user manual.
In short:

  • “definitely lost” means your program is leaking memory – fix those leaks!

  • “indirectly lost” means your program is leaking memory in a pointer-based structure. (E.g. if the root node of a binary tree is “definitely lost”, all the children will be “indirectly lost”.) If you fix the “definitely lost” leaks, the “indirectly lost” leaks should go away.

  • “possibly lost” means your program is leaking memory, unless you’re doing unusual things with pointers that could cause them to point into the middle of an allocated block; see the user manual for some possible causes. Use –show-possibly-lost=no if you don’t want to see these reports.

  • “still reachable” means your program is probably ok – it didn’t free some memory it could have. This is quite common and often reasonable. Don’t use –show-reachable=yes if you don’t want to see these reports.

  • “suppressed” means that a leak error has been suppressed. There are some suppressions in the default suppression files. You can ignore suppressed errors.

分析

  • “definitely lost”:确认丢失。程序中存在内存泄露,应尽快修复。当程序结束时如果一块动态分配的内存没有被释放且通过程序内的指针变量均无法访问这块内存则会报这个错误。

  • “indirectly lost”:间接丢失。当使用了含有指针成员的类或结构时可能会报这个错误。这类错误无需直接修复,他们总是与”definitely lost”一起出现,只要修复”definitely lost”即可。例子可参考我的例程。

  • “possibly lost”:可能丢失。大多数情况下应视为与”definitely lost”一样需要尽快修复,除非你的程序让一个指针指向一块动态分配的内存(但不是这块内存起始地址),然后通过运算得到这块内存起始地址,再释放它。例子可参考我的例程。当程序结束时如果一块动态分配的内存没有被释放且通过程序内的指针变量均无法访问这块内存的起始地址,但可以访问其中的某一部分数据,则会报这个错误。

  • “still reachable”:可以访问,未丢失但也未释放。如果程序是正常结束的,那么它可能不会造成程序崩溃,但长时间运行有可能耗尽系统资源,因此笔者建议修复它。如果程序是崩溃(如访问非法的地址而崩溃)而非正常结束的,则应当暂时忽略它,先修复导致程序崩溃的错误,然后重新检测。

  • “suppressed”:已被解决。出现了内存泄露但系统自动处理了。可以无视这类错误。这类错误我没能用例程触发,看官方的解释也不太清楚是操作系统处理的还是valgrind,也没有遇到过。所以无视他吧~

代码示例

#include <stdio.h>
#include <stdlib.h>

void *g_p1;
int *g_p2;
int ** fun1(void)
{
//付给了局部变量, 函数结束而不释放,为肯定丢失.
//把函数尾部语句return p; 改为return 0;更能说明这个问题.
int **p=(int **)malloc(16);
g_p1=malloc(20); //付给了全局变量, 内存可以访问
g_p2=(int*)malloc(30);
g_p2++; //付给了全局变量, 内存可以访问,但是指针被移动过,为可能丢失
p[1]=(int *)malloc(40); //如果p丢失了,则p[1]为间接丢失.
return p;
}
int main(int argc, char *argv[])
{

int **p=fun1();
// free(g_p1); //如果不free, 将会有 still reachable 内存泄露
// free(--g_p2);//如果不free, 将会有 possibly lost 内存泄露
// free(p[1]); //如果不free, 将会有 indirectly lost 内存泄露
// free(p); //如果不free, 将会有 definitely lost内存泄露
return 0;
}

执行编译命令g++ val_test.cpp -o v, 然后

当执行valgrind ./v 命令之后的简易内存错误报告 :

==4765== Memcheck, a memory error detector
==4765== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4765== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==4765== Command: ./v
==4765== 
==4765== 
==4765== HEAP SUMMARY:
==4765==     in use at exit: 106 bytes in 4 blocks
==4765==   total heap usage: 4 allocs, 0 frees, 106 bytes allocated
==4765== 
==4765== LEAK SUMMARY:
==4765==    definitely lost: 16 bytes in 1 blocks
==4765==    indirectly lost: 40 bytes in 1 blocks
==4765==      possibly lost: 30 bytes in 1 blocks
==4765==    still reachable: 20 bytes in 1 blocks
==4765==         suppressed: 0 bytes in 0 blocks
==4765== Rerun with --leak-check=full to see details of leaked memory
==4765== 
==4765== For counts of detected and suppressed errors, rerun with: -v
==4765== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
b@b-VirtualBox:~/tc/valgrind_test$ valgrind --leak-check=full
valgrind: no program specified
valgrind: Use --help for more information.

当执行valgrind --leak-check=full ./v 命令之后的详细内存错误报告 :

==4767== Memcheck, a memory error detector
==4767== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4767== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==4767== Command: ./v
==4767== 
==4767== 
==4767== HEAP SUMMARY:
==4767==     in use at exit: 106 bytes in 4 blocks
==4767==   total heap usage: 4 allocs, 0 frees, 106 bytes allocated
==4767== 
==4767== 30 bytes in 1 blocks are possibly lost in loss record 2 of 4
==4767==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4767==    by 0x40055E: fun1() (val_test.cpp:12)
==4767==    by 0x4005AB: main (val_test.cpp:20)
==4767== 
==4767== 56 (16 direct, 40 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
==4767==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4767==    by 0x40053F: fun1() (val_test.cpp:10)
==4767==    by 0x4005AB: main (val_test.cpp:20)
==4767== 
==4767== LEAK SUMMARY:
==4767==    definitely lost: 16 bytes in 1 blocks
==4767==    indirectly lost: 40 bytes in 1 blocks
==4767==      possibly lost: 30 bytes in 1 blocks
==4767==    still reachable: 20 bytes in 1 blocks
==4767==         suppressed: 0 bytes in 0 blocks
==4767== Reachable blocks (those to which a pointer was found) are not shown.
==4767== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==4767== 
==4767== For counts of detected and suppressed errors, rerun with: -v
==4767== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

总结

  • 由局部变量指向的内存,如果不释放为肯定丢失,
  • 由此指针而引起的后续内存泄露,为间接丢失.
  • 由全局变量指向的内存如果不被释放,为still reachable,
  • 如果该变量改动过, 为可能丢失.

是啊,局部变量是栈变量,如果你不能把这个栈变量处理好,出了这个函数,指针地址就丢失了,这时那是肯定丢失了.

如果你付给的地址是全局变量,倒是可以访问,叫still reachable

但是如果你这个全局变量的值改动过, 那只有你知道怎样正确访问这块内存,别人可能就访问不到了,这叫可能丢失.

由肯定丢失而引起的进一步的内存丢失为间接丢失.

解决内存泄漏的顺序

所以碰到问题你首先要解决什么问题?

肯定丢失,
然后是可能丢失,
然后间接丢失,
然后still reachable!!!

1…2021222324252627282930313233343536
Mike

Mike

🚙 🚗 💨 💨 If you want to create a blog like this, just follow my open-source project, "hexo-theme-neo", click the GitHub button below and check it out ^_^ . It is recommended to use Chrome, Safari, or Edge to read this blog since this blog was developed on Edge (Chromium kernel version) and tested on Safari.

11 categories
287 posts
110 tags
about
GitHub Spotify
© 2013 - 2025 Mike