private void grow() {
		HugeLongArray oldAddresses = addresses;
		
		// instead of just doubling the size - this gives more prime number sizes which tend to distribute hash codes better
		int newCapacity = oldAddresses.size() <= 1 ? 2 : oldAddresses.size() * 2 - 1;
		initialize(newCapacity);
		
		for (int oldAddressIndex = 0; oldAddressIndex < oldAddresses.size(); oldAddressIndex++) {
			long address = oldAddresses.get(oldAddressIndex);
			if (address != NO_ADDRESS) {
				boolean cheap = false;
				int entriesCount = getEntriesCount(address);
				if (entriesCount == 1) {
					// maybe possible to do a cheap copy of key/value pair
					int key = getKeyInsideIndex(address, 0);
					int index = hashIndex(key);
					if (addresses.get(index) == NO_ADDRESS) {
						// possible to do a cheap copy, since only 1 key/value pair and hashIndex in new growing map is still empty - just point to the old address
						addresses.set(index, address);
						countHashCodes++;
						cheap = true;
					}
				}
				
				if (!cheap) {
					// extract all key/value pairs at 'address' and put then into the growing new map
					byte[] data = memoryManager.read(address);
					memoryManager.free(address);
					ByteBuffer byteBuffer = ByteBuffer.wrap(data);
					
					int count = byteBuffer.getInt();
					for (int i = 0; i < count; i++) {
						int storedKey = byteBuffer.getInt();
						int storedArrayLength = byteBuffer.getInt();
						long[] storedArray = new long[storedArrayLength];
						for (int j = 0; j < storedArrayLength; j++) {
							storedArray[j] = byteBuffer.getLong();
						}
						put(storedKey, storedArray);
						size--; // correct the size that was modified by put() 
					}		
				}
			}
		}
	}