///////////////////////////////////////////////////////////////////// find free chunks and reset chunk size so they can be reused by different sized allocations do not look at blockFreeList (TFreeListGroup has same size for any allocations)
| 775 | // find free chunks and reset chunk size so they can be reused by different sized allocations |
| 776 | // do not look at blockFreeList (TFreeListGroup has same size for any allocations) |
| 777 | static bool DefragmentMem() { |
| 778 | if (!EnableDefrag) { |
| 779 | return false; |
| 780 | } |
| 781 | |
| 782 | IncrementCounter(CT_DEGRAGMENT_CNT, 1); |
| 783 | |
| 784 | int* nFreeCount = (int*)SystemAlloc(N_CHUNKS * sizeof(int)); |
| 785 | if (Y_UNLIKELY(!nFreeCount)) { |
| 786 | //__debugbreak(); |
| 787 | NMalloc::AbortFromCorruptedAllocator("debugbreak"); |
| 788 | } |
| 789 | memset(nFreeCount, 0, N_CHUNKS * sizeof(int)); |
| 790 | |
| 791 | TFreeListGroup* wholeLists[N_SIZES]; |
| 792 | for (int nSizeIdx = 0; nSizeIdx < N_SIZES; ++nSizeIdx) { |
| 793 | wholeLists[nSizeIdx] = (TFreeListGroup*)globalFreeLists[nSizeIdx].GetWholeList(); |
| 794 | for (TFreeListGroup* g = wholeLists[nSizeIdx]; g; g = g->Next) { |
| 795 | for (auto pData : g->Ptrs) { |
| 796 | if (pData) { |
| 797 | uintptr_t nChunk = (pData - ALLOC_START) / N_CHUNK_SIZE; |
| 798 | ++nFreeCount[nChunk]; |
| 799 | Y_ASSERT_NOBT(chunkSizeIdx[nChunk] == nSizeIdx); |
| 800 | } |
| 801 | } |
| 802 | } |
| 803 | } |
| 804 | |
| 805 | bool bRes = false; |
| 806 | for (size_t nChunk = 0; nChunk < N_CHUNKS; ++nChunk) { |
| 807 | int fc = nFreeCount[nChunk]; |
| 808 | nFreeCount[nChunk] = 0; |
| 809 | if (chunkSizeIdx[nChunk] <= 0) |
| 810 | continue; |
| 811 | int nEntries = N_CHUNK_SIZE / nSizeIdxToSize[static_cast<int>(chunkSizeIdx[nChunk])]; |
| 812 | Y_ASSERT_NOBT(fc <= nEntries); // can not have more free blocks then total count |
| 813 | if (fc == nEntries) { |
| 814 | bRes = true; |
| 815 | nFreeCount[nChunk] = 1; |
| 816 | } |
| 817 | } |
| 818 | if (bRes) { |
| 819 | for (auto& wholeList : wholeLists) { |
| 820 | TFreeListGroup** ppPtr = &wholeList; |
| 821 | while (*ppPtr) { |
| 822 | TFreeListGroup* g = *ppPtr; |
| 823 | int dst = 0; |
| 824 | for (auto pData : g->Ptrs) { |
| 825 | if (pData) { |
| 826 | uintptr_t nChunk = (pData - ALLOC_START) / N_CHUNK_SIZE; |
| 827 | if (nFreeCount[nChunk] == 0) |
| 828 | g->Ptrs[dst++] = pData; // block is not freed, keep pointer |
| 829 | } |
| 830 | } |
| 831 | if (dst == 0) { |
| 832 | // no valid pointers in group, free it |
| 833 | *ppPtr = g->Next; |
| 834 | blockFreeList.Free(g); |
no test coverage detected