Yuerer's Blog

钰儿的Blog

为什么要实现内存池?

一方面 是为了减少 调用 malloc() 的次数(尽管 malloc() 不慢) 但是调多了 会产生(外碎片)

另一方面 是因为 每次用 malloc() 分配到的内存 是要交税的 就是上一节中讲的 cookie 里面记录着 这一块内存的大小信息(内碎片) 特别是在频繁申请小内存的时候尤为明显

最终 pool_allocator 版本

具体代码可见 Memory_Pool

原理可见 C++ 内存管理 之 STL内存分配实现原理

阅读全文 »

本文主要讲讲 GNU-C++ 4.9 下的扩展内存分配器

首先 GNU-C++ 4.9 有 7 个扩展的内存分配器

  • new_allocator
  • malloc_allocator
  • pool_allocator
  • __mt_alloc
  • array_allocator
  • debug_allocator
  • bitmap_allocator

主要看看 pool_allocator array_allocator bitmap_allocator

以下源码都可在 .../ext/*.h 下找到 我将其进行了适当的 删减和修改

__gnu_cxx::new_allocator

直接用 ::operator new::operator delete 实现出来的 好处是 可以被重载 没啥特色

1
2
3
4
5
6
7
8
9
10
template<typename _Tp>
class new_allocator {
public:
pointer allocate(size_type __n, const void* = 0) {
return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
}
void deallocate(pointer __p, size_type) {
::operator delete(__p);
}
};
阅读全文 »

本文主要讲的是 各个C++版本 中的STL标准库中的默认内存分配器 的 各种实现

VC6 标准分配器实现

VC6 它什么内存管理都没做 直接调用的 operator newoperator new 内部实际上 调用的就是 malloc

此外 VC6 下 是以元素为单位 比如 int 的话 他就会分配 512 ints 如果是 double 则会分配 512 doubles

GNU-C++ 2.9 以字节为单位 GNU-C++ 4.9 以元素为单位 在 G2.9 中的容器默认分配器 被移到了 pool_allocator

注意 G2.9 的标准分配器 和 容器默认分配器 不一样噢!

GNU-C++ 2.9 标准分配器实现

std::allocator 标准分配器 也是什么都没做

但是 G2.9 容器使用的分配器 不是上面的那个 std::allocator 而是 std::alloc

阅读全文 »

为什么要叫原生版本?

因为我觉得这一块是 C++ 自带的表达式 表达式里面 去调用 C语言的 CRT 库中的 mallocfree 但这篇 只讲自带的表达式 而不去深究 CRT 中的内存分配函数 所以只叫原生版本

常见的内存分配

分配释放类属可否重载
malloc()free()C 函数
newdeleteC++ 表达式
::operator new()::operator delete()C++ 函数
allocator::allocate()allocator::deallocate()C++ 标准库自由设计搭配的容器

使用示例

其中 ::operator new() 和 ::operator delete() 调用了 malloc() 和 free()

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
    void *p1 = malloc(512);
free(p1);

complex<int> *p2 = new complex<int>;
delete p2;

void *p3 = ::operator new(512);
::operator delete(p3);

#ifdef _MSC_VER
// 属于 non-static 要先实例化object再调用
int *p4 = allocator<int>().allocate(3, (int*)0);
allocator<int>().deallocate(p4, 3);
#endif

#ifdef __GUNC__
// 早期 GNU-C++ 2.9 版本
// void *p4 = alloc::allocate(512);
// alloc::deallocate(p4, 512);
// alloc 换名字了
void *p5 = __gnu_cxx::__pool_alloc<int>().allocate(9);
__gnu_cxx::__pool_alloc<int>().deallocate((int*)p5, 9);
// 4.9 版本之后
void *p4 = allocator<int>().allocate(7);
allocator<int>().deallocate((int*)p4, 7);

#endif
阅读全文 »

VSCode 近期推出了 Remote-SSH 这个工具 使得 Linux开发者 能够在本地(Windows 机)上直接对开发机源码进行修改 简直拯救了一大批人啊… 但是却没有提到 如何离线安装 因此本文可能是最早 尝试离线安装的教程

离线安装

  1. 本地上下载好 VSCode Insiders
  2. 安装 Remote-SSH 插件
阅读全文 »

首先 IPv4 资源是非常稀少的 大约只有 43亿 而且这还是包括了私有IP地址段的 其次 IP地址分为了五类 其中 D类地址没有主机标识 常被用于广播 E类被保留 我们不去管它

那就只剩下了 A B C 三类 问题是 A类和B类的链路允许非常多的计算机连接 实际网络架构上 根本用不到那么多 这就造成了IPv4的浪费 这个时候 子网掩码出现了

子网掩码的意义

将 A B C类网络进行更细的划分 避免浪费 IPv4地址 也可以把小的网络归并成大的网络即超网

子网掩码的理解

假设有一个财主 他有256间房子 房子的编号是 0~255 然后它的房子都在192.168.0这一条街上 现在他有8个儿子 要分家 则相当于 每个人都分得32间房子

阅读全文 »

在天朝这么久 你曾为网络状况不佳而烦恼过吗? 平时使用的 Shadowsocks 是怎么实现?
这篇讲的就是 如何用 Golang 实现一个最为基础的 Shdowsocks 的功能的软件 我将本文实现的软件取名叫 GoSocksProxy

老规矩先介绍一遍 什么是 GoSocksProxy? 它是怎么来的?

GoSocksProxy

一个 Golang 所写的网络混淆代理 是学习 SOCKS5 协议时的副产品 为此还做了一张图

GoSocksProxy

阅读全文 »

首先讲讲数在计算机上的表示

数的机器表示

众所周知 机器很笨 它是不认识什么 有符号数 和 无符号数的 它只认识 二进制串 那么在计算机上 是如何表示 有符号数和无符号数的呢?

计算机不区分有符号数和无符号数

首先在计算机眼中 它确确实实只认识 二进制串 二进制串所表示的数 是有符号数还是无符号数 取决于 用户(编码者)怎么看 当你认为 0xffff 为正数时 它就是 65535 当你认为 0xffff 为负数时 就为 -1

其次 在计算机中 它会将送进来的数 统一用补码计算 使用补码计算就不用区分 是有符号数还是无符号数 因为补码的加减法的规则相同

阅读全文 »

练习0:填写已有实验

请把你做的实验代码填入本实验中代码中有“LAB1”/“LAB2”/“LAB3”/“LAB4”/“LAB5”/“LAB6” /“LAB7”的注释相应部分。并确保编译通过。注意:为了能够正确执行lab8的测试应用程序,可能需对已完成的实验1/2/3/4/5/6/7的代码进行进一步改进。

1
2
3
4
5
6
7
8
9
10
11
12
vmm.c default_pmm.c pmm.c proc.c swap_fifo.c trap.c check_sync.c
proc.c:
static struct proc_struct *alloc_proc(void) {
// 初始化 PCB 下的 fs(进程相关的文件信息)
proc->filesp = NULL;
}
int do_fork(uint32_t clone_flags, uintptr_t stack, struct trapframe *tf) {
// 使用 copy_files()函数复制父进程的fs到子进程中
if (copy_files(clone_flags, proc) != 0) {
goto bad_fork_cleanup_kstack;
}
}
阅读全文 »
0%