C++的内存模型
这些文章对于内存模型的讲解非常好,建议阅读,本文整理一下相关的知识点。
来源于CSAPP第五章
1 | //可以设计不同的数据类型来测量程序性能 |
上述代码的汇编码如下:
1 | # vmovsd代表从指定的位置读数据 |
进入循环后,从内存中读数据,和data[i]
乘,再写入到内存中。这种操作比较浪费,因为循环下次读的数据是上次写入内存的数据。
可以用一个临时变量来存储结果,等循环结束后再写入内存中。这样每次循环可以减少一次写的过程。
1 | void combin4(vec_ptr v, data_t* dest) |
值得注意的是,从代码层面看指令是一条一条执行的,但是实际处理器中是同时对多条指令求值,这种现象称为指令级并行。所以这两种操作限制了程序的瓶颈:第一个是指令必须按照严格顺序执行,那就会遇到延迟界限;第二个是吞吐量界限(取决于处理器原始计算能力)。
看了一篇博客,个人感觉很有帮助,目前转载过来留存,正在征询作者意见,如果不同意就删掉啦。
原文链接:https://blog.csdn.net/kenanxiuji/article/details/48547285
最近,我一直忙于追踪分析,咱公司高并发代理服务器内存一直占用过高的问题。该问题表现如下,使用python脚本压测,服务器使用的物理内存一直飙升很快上G、虚拟内存更是高达数10G,没有下降的趋势。当压测程序停止运行后,整个服务占用的物理内存以及虚拟内存并没有下降的趋势。
首先简诉咱服务器运行的平台是centos-6.3(linux-2.6.32),该服务器是多进程的,基于libevent网络通信框架,以bufferevent为核心,并使用google::protobuf通信协议进行数据传输。
根据top -p /pmap -dx 等命令,检测出咱服务器进程内存占用很高,我揣测产生了内存泄露。内存泄露有两种,第一种是进程一直持有不在需要或者使用的内存,这不是狭义的内存泄露,因为没有野指针的产生,可以归为广义的内存泄露,这是危害最大的,也是很难捕捉的内存泄露,使用valgrind等工具是没有办法检测出来的;第二种是进程通过malloc、new分配了堆内存,却由于各种原因,未能释放,这是狭义的内存泄露,可以通过valgrind等内存泄露工具检测到的。
在makefile中用了-lmysqlclient
,但是会报错/usr/bin/ld: cannot find -lmysqlclient
。
先在/user/lib中查,发现没有,用find / -name mysqlclient发现也没有。
于是借助搜索引擎去查,结果国内论坛怎么也没找到解决办法,不得已去看官方C API,发现让重新下载解压,遂放弃。
随后又在stack overflow搜索了一下,果不其然,成功解决。附上解决方案:https://stackoverflow.com/questions/15958612/libmysqlclient-a-is-nowhere-to-be-found
在知乎看(搜索)到这么一个问题:如何用redis/memcache做Mysql缓存层?刚好最近学的项目只是用到了mysql,这里学习整理一下缓存的知识。PS:强烈建议学习陈皓大神的文章以及阅读英文原文,中文博客知识需要进行筛选。
知乎问题https://www.zhihu.com/question/27738066
陈皓(左耳朵耗子)的文章https://coolshell.cn/articles/17416.html
首先要讨论的是,缓存删除还是更新的问题。什么情况下选择删除,什么情况下选择更新?
缓存存储的value是序列化的对象
序列化和反序列化需要消耗cpu的资源,删除缓存成本更低,等出现下次数据汇源时再更新。
高并发的场景
两个并发操作,一个查询缓存,一个更新操作。先更新(选择删除缓存),再查询,此时无法命中缓存,会先把老的数据从数据库读出放入缓存中,然后更新数据库。此时缓存中是脏的数据,并且一直这样脏下去。所以,这种场景应该选择缓存更新,而不是删除Cache后再从数据库更新。
1 | template< |
Key代表键值(key),T是根据哈希函数得到的值(value),Hash是哈希函数的函数对象,KeyEqual是等比函数的函数对象,通过"=="
来判断两个key是否相等。
想实现自定义的键类型,必须实现hash函数和等比函数。
在网上找到的转载的英文资料,附上自己的一些理解点击连接
Both the malloc()
and the calloc()
functions are used to allocate dynamic memory. Each operates slightly different from the other.
malloc和calloc函数都用来分配动态内存,他们之间的差别很小
malloc()
takes a size and returns a pointer to a chunk of memory at least that big:
void *malloc( size_t size );
malloc返回至少有申请内存大小的一块内存(可能更大)
calloc()
takes a number of elements, and the size of each, and returns a pointer to a chunk of memoryat least big enough to hold them all:
void *calloc( size_t numElements, size_t sizeOfElement );
calloc返回至少有多块内存大小之和的内存(可能更大)
There are one major difference and one minor difference between the two functions. The major difference is that malloc()
does not initialize the allocated memory. The first time malloc()
gives you a particular chunk of memory, the memory might be full of zeros. If memory has been allocated, freed, and reallocated, it probably has whatever junk was left in it. That means, unfortunately, that a program might run in simple cases (when memory is never reallocated) but break when used harder (and when memory is reused).
他们之间最主要的差别是,malloc不初始化分配的内存,可能内存中充满的是零。如果内存已经被分配、释放或重新分配过,它可能存放着未知的内容。这意味着当这块内存从申请,修改,再到被重新分配,包含未知的内容会导致程序崩溃
calloc()
fills the allocated memory with all zero bits. That means that anything there you are going to use as a char or an int of any length, signed or unsigned, is guaranteed to be zero. Anything you are going to use as a pointer is set to all zero bits. That is usually a null pointer, but it is not guaranteed.Anything you are going to use as a float or double is set to all zero bits; that is a floating-point zero on some types of machines, but not on all.
calloc()用0 bits填充分配的内存,所以不需要初始化。通常这是一个空指针,但并不保证一定是。使用float或double类型被置为zero bits,在某些机器上是浮点零,但不保证一定是。
The minor difference between the two is that calloc()
returns an array of objects; malloc()
returns one object. Some people use calloc()
to make clear that they want an array.
一些细小差别是calloc()返回一个包含对象的数组,而malloc返回一个对象。
设计buffer可以从易用性和性能两方面考虑,muduo的buffer更偏向于易用性。
(char* p, int len)
size()
可以自动增长,不是固定大小的数组std::vector<int>
来保存数据input buffer
:连接从socket中读取数据,写入input buffer
;客户代码从中读取数据output buffer
:客户代码把数据写入output buffer
,连接从output buffer
中读数据并写入socket在学习muduo如何实现Buffer之前,先阅读Buffer.h
头文件中所需要的依赖。
基本类型的声明,如muduo::string
;
具体有:
1 | inline void memZero(void* p, size_t n); |
约瑟夫环来源于犹太历史学家Josephus所讲述的一个故事。罗马人占领某地后,39个犹太人和Josephus以及他的朋友躲到了一个洞中。
他们决定围成一个圈,逐个自杀也不要被罗马人抓住。自杀规则是从第一个人开始,数到3的人就自杀,然后由下一个人重新报数。
Josephus和他的朋友不想自杀,他们自己选择了两个位置,活到了最后。
将这个问题抽象以后,在LeetCode上有这么一道题圆圈中最后剩下的数字
在我做笔试的经历中,出现了题目的变种,变化之处在于删除的数字间隔是变化的,随着删除个数而增长。