docs: @Override
      public void free(AllocationPoint point) {
          switch (point.getAllocationStatus()) {
              case HOST: {
                  // cudaFreeHost call here
                  long reqMem = AllocationUtils.getRequiredMemory(point.getShape());
                  val nativeOps = NativeOpsHolder.getInstance().getDeviceNativeOps();
  
                  long result = nativeOps.freeHost(point.getPointers().getHostPointer());
                  if (result == 0) {
                      throw new RuntimeException("Can't deallocate [HOST] memory...");
                  }
  
                  MemoryTracker.getInstance().decrementAllocatedHostAmount(reqMem);
              }
                  break;
              case DEVICE: {
                  if (point.isConstant())
                      return;
  
                  long reqMem = AllocationUtils.getRequiredMemory(point.getShape());
  
                  val nativeOps = NativeOpsHolder.getInstance().getDeviceNativeOps();
                  AllocationsTracker.getInstance().markReleased(AllocationKind.GENERAL, point.getDeviceId(), reqMem);
  
                  val pointers = point.getPointers();
  
                  long result = nativeOps.freeDevice(pointers.getDevicePointer(), 0);
                  if (result == 0)
                      throw new RuntimeException("Can't deallocate [DEVICE] memory...");
  
                  MemoryTracker.getInstance().decrementAllocatedAmount(point.getDeviceId(), reqMem);
              }
                  break;
              default:
                  throw new IllegalStateException("Can't free memory on target [" + point.getAllocationStatus() + "]");
          }
      }