Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Freeing memory allocated with newCString

As library docs say CString created with newCString must be freed with free function. I have been expecting that when CString is created it would take some memory and when it is released with free memory usage would go down, but it didn't! Here is example code:

module Main where

import Foreign
import Foreign.C.String
import System.IO

wait = do
  putStr "Press enter" >> hFlush stdout
  _ <- getLine
  return ()

main = do
  let s = concat $ replicate 1000000 ['0'..'9']
  cs <- newCString s
  cs `seq` wait   -- (1)

  free cs
  wait   -- (2)

When program stopped at (1), htop program showed that memory usage is somewhere around 410M - this is OK. I press enter and the program stops at line (2), but memory usage is still 410M despite cs has been freed!

How is this possible? Similar program written in C behaves as it should. What am I missing here?

like image 436
Vladimir Matveev Avatar asked May 09 '12 09:05

Vladimir Matveev


People also ask

Can you free memory allocated with new?

You must use delete operator to deallocate memory when it is allocated by new operator.

How do you free the allocated memory?

The free() function is used to free the memory which is allocated previously using malloc() or calloc(). Syntax: free(mem_ptr);

What happens if you free already freed memory?

If you attempt to read or write to memory that was previously freed, the result will be a conflict and the program will generate a memory error. For example, if a program calls the free() function for a particular block and then continues to use that block, it will create a reuse problem when a malloc() call is made.

Do you need to free std::string?

std::string is just a normal class1, so the usual rules apply. If you allocate std::string objects on the stack, as globals, as class members, ... you don't need to do anything special, when they go out of scope their destructor is called, and it takes care of freeing the memory used for the string automatically.


1 Answers

The issue is that free just indicates to the garbage collector that it can now collect the string. That doesn't actually force the garbage collector to run though -- it just indicates that the CString is now garbage. It is still up to the GC to decide when to run, based on heap pressure heuristics.

You can force a major collection by calling performGC straight after the call to free, which immediately reduces the memory to 5M or so.

E.g. this program:

import Foreign
import Foreign.C.String
import System.IO
import System.Mem

wait = do
  putStr "Press enter" >> hFlush stdout
  _ <- getLine
  return ()

main = do
  let s = concat $ replicate 1000000 ['0'..'9']
  cs <- newCString s
  cs `seq` wait   -- (1)

  free cs
  performGC
  wait   -- (2)

Behaves as expected, with the following memory profile - the first red dot is the call to performGC, immediately deallocating the string. The program then hovers around 5M until terminated.

enter image description here

like image 190
Don Stewart Avatar answered Sep 16 '22 14:09

Don Stewart