Here is the solution that I was discussing in the comments. It's very similar in concept to your's except it tries to reduce the number of DML and SOQL statements by grouping the Attachments into batches of 5MB (this will need adjusting, I just chose it to prove the concept).
The code could do with cleaning up a bit, and you'll want to change how the ParentIds are selected/assigned, but hopefully the concept is clear:
List<List<Id>> batches = new List<List<Id>>();
List<Integer> batchSizes = new List<Integer>();
for(Attachment attachment : [SELECT Id, BodyLength from Attachment WHERE ParentId = '5002000000ahX5f'])
{
Boolean batched = false;
for(Integer i = 0; i < batches.size(); i++)
{
Integer batchSize = batchSizes[i];
if(batchSize + attachment.BodyLength < 10000000)
{
batches[i].add(attachment.Id);
batchSizes[i] += attachment.BodyLength;
batched = true;
break;
}
}
if(!batched)
{
batches.add(new List<Id>{attachment.Id});
batchSizes.add(attachment.BodyLength);
}
System.debug('>>>first loop heap=' + Limits.getHeapSize());
}
for(List<Id> batchIds : batches)
{
List<Attachment> attachmentsToInsert = new List<Attachment>();
for(Attachment attachment : [SELECT Name, Body FROM Attachment WHERE Id IN :batchIds])
{
attachmentsToInsert.add(new Attachment(Name = attachment.Name, Body = attachment.Body, ParentId = '5002000000ahX5v'));
}
System.debug('>>> second loop heap=' + Limits.getHeapSize());
insert attachmentsToInsert;
}
The output for an object with 5 Attachments (4.28MB, 1.23MB, 1.24MB, 3.59MB, 4.29MB) is as follows:
>>>first loop heap=1871
>>>first loop heap=1917
>>>first loop heap=1955
>>>first loop heap=1993
>>>first loop heap=2015
>>> second loop heap=4503453
>>> second loop heap=2589001
>>> second loop heap=4489577
>>> second loop heap=3759972
Number of SOQL queries: 5 out of 100
Number of DML statements: 4 out of 150
In this case it has only saved 1 DML, but with a lot of small Attachments or increasing the limit this will save a lot more.
For example, using a limit of 10MB gives you the following:
>>>first loop heap=1871
>>>first loop heap=1901
>>>first loop heap=1939
>>>first loop heap=1961
>>>first loop heap=1983
>>> second loop heap=9549616
>>> second loop heap=5788869
Number of SOQL queries: 3 out of 100
Number of DML statements: 2 out of 150