You should definitely not create a separate entity for each block in the terrain. Entities have a huge overhead in terms of memory. Instead, use something more compact, like a bunch of bytes, shorts or integers (depending on how many types of blocks you have, you could also use a struct if you need to keep some additional data) in a multi dimensional array (or a single dimensional one if you really need to save memory).
So, you'd basically have chunk objects, each containing an array of values. From here you can go in 2 different directions.
- If the chunks don't change that much, then you should generate a single mesh out of the cubes where you remove the invisible faces and you only need to update this mesh if the blocks change.
- If the chunks change frequently, then you should use instancing to render the cubes. This way you don't need to change a mesh every time the blocks change. You should try to avoid rendering invisible cubes and possibly faces, but the latter one wouldn't help too much over the former if the terrain's mostly solid.
If you did all that, but you still hit the memory cap (I doubt it though), then try a different method instead. Create a 3d texture containing the terrain information and render it using a geometry shader. This way you only use the VRAM instead of the RAM, but it's going to be slower to update the terrain.