loop through all posts memory error

The posts are still held in memory under WordPress’ cache mechanism (even though you replace $posts on every loop) – delete each one after operating on it:

# do some echoing with the $post

# wipe post from memory
wp_cache_delete( $post->ID, 'posts' );
wp_cache_delete( $post->ID, 'post_meta' );

Pro tip: save some needless queries with no_found_rows => true in your query args.

And if you’re not using categories/tags in your loop, save even more queries (& memory) with update_post_term_cache => false in your query args.