docs: @Override
      public void free(AllocationPoint point) {
          if (point.getAllocationStatus() == AllocationStatus.DEVICE) {
              super.free(point);
          } else {
              AllocationShape shape = point.getShape();
              long reqMemory = AllocationUtils.getRequiredMemory(shape);
  
              // we don't cache too big objects
              if (reqMemory > CudaEnvironment.getInstance().getConfiguration().getMaximumHostCacheableLength() || zeroCachedAmount.get() >= CudaEnvironment.getInstance().getConfiguration().getMaximumHostCache()) {
                  super.free(point);
                  return;
              }
  
              ensureCacheHolder(shape);
  
              /*
                  Now we should decide if this object can be cached or not
               */
              CacheHolder cache = zeroCache.get(shape);
  
              // memory chunks < threshold will be cached no matter what
              if (reqMemory <= FORCED_CACHE_THRESHOLD) {
                  Pointer.memset(point.getHostPointer(), 0, reqMemory);
                  cache.put(new CudaPointer(point.getHostPointer().address()));
              } else {
                  long cacheEntries = cache.size();
                  long cacheHeight = zeroCache.size();
  
                  // total memory allocated within this bucket
                  long cacheDepth = cacheEntries * reqMemory;
  
                  Pointer.memset(point.getHostPointer(), 0, reqMemory);
                  cache.put(new CudaPointer(point.getHostPointer().address()));
              }
  
              MemoryTracker.getInstance().decrementAllocatedHostAmount(reqMemory);
              MemoryTracker.getInstance().incrementCachedHostAmount(reqMemory);
          }
      }