Explorar el Código

feat: 添加 MyAllocator 的代码解释

liucong5 hace 2 años
padre
commit
924dfd6858

BIN
cpp/img/Memory_09.png


+ 2 - 1
cpp/temp-cpp-proj/.gitignore

@@ -1,4 +1,5 @@
 .vs
 bin
 obj
-x64
+x64
+Debug

+ 2 - 0
cpp/temp-cpp-proj/temp-cpp-proj/src/CustomAllocator.cpp

@@ -15,11 +15,13 @@ public:
 private:
 	obj* freeStore = nullptr;
 	const int CHUNK = 5;	// 标准库是20
+	const int min_size = 8;
 };
 
 void* MyAllocator::allocate(size_t size)
 {
 	obj* p = nullptr;
+	size =  size > min_size ? size : min_size;
 	if (!freeStore) {
 		size_t chunk = CHUNK * size;
 		freeStore = p = (obj*)malloc(chunk);

+ 2 - 0
cpp/temp-cpp-proj/temp-cpp-proj/temp-cpp-proj.vcxproj

@@ -104,10 +104,12 @@
       <SDLCheck>true</SDLCheck>
       <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <ConformanceMode>true</ConformanceMode>
+      <StructMemberAlignment>Default</StructMemberAlignment>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalOptions>/ALIGN:4 %(AdditionalOptions)</AdditionalOptions>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+ 11 - 3
cpp/内存机制.md

@@ -638,11 +638,13 @@ public:
 private:
 	obj* freeStore = nullptr;
 	const int CHUNK = 5;	// 标准库是20
+	const int min_size = 8;
 };
 
 void* MyAllocator::allocate(size_t size)
 {
 	obj* p = nullptr;
+	size =  size > min_size ? size : min_size;
 	if (!freeStore) {
 		size_t chunk = CHUNK * size;
 		freeStore = p = (obj*)malloc(chunk);
@@ -677,7 +679,7 @@ public:
 	static MyAllocator myAlloc;
 
 public:
-    Goo(long l): L(l) {}
+	Goo(long l) : L(l) {}
 	static void* operator new(size_t size) {
 		return myAlloc.allocate(size);
 	}
@@ -714,7 +716,13 @@ int main() {
 }
 ```
 
-> 上面的代码可能运行不了(与编译器版本有关),但是可以表达我们对 allocator 运行的机制
-
 使用这种写法的 allocator 的内存分配器可以给其他任意类型的对象使用,对象无需再关注内存如何分配,而是仅仅需要引入 `MyAllocator` 并且在 `operator new` 和 `operator delete` 中使用即可
 
+这里需要注意的是自定义的 `MyAllocator` 有一个属性 `min_size = 8`,在 x64 的平台上指针占 **8个字节**,上述代码的 Goo 对象占 **4个字节**,也就是说在地址运算的时候会将前后两个 Goo 对象的内存合并为一个地址,最后出现错误
+
+![](img/Memory_09.png)
+
+以上图为例,一格黑色方块就是一个 `Goo` 对象的大小4字节,是提前为未来的 `Goo` 创建出来的内存空间。理论上来说第一格内存地址为 `D0`,其 `next` 指针指向 `D4`,但是实际运行时由于地址为 **8字节**,所以第一格的 `next` 指针的值其实是 `D0D4`,而这个地址其实是一个未知地址,最后导致运行报错
+
+上述代码其实也很明显,将 `Goo` 的内存块 `cast` 成 `Obj` 对象来管理空闲空间,以此达到节省内存空间的效果。当内存块需要被使用时,其会从空闲链表中移出并设置,此时就与链表无关的,所以也不用管 `next` 的值。等到 Goo 被 delete 时,其会从 Goo 再次转为 `Obj` 链表节点,这时也不用管 `Goo` 对象的值是多少,因为此时 Goo 对象已经无效了
+