금년도 들어서 가장 해결하기 어려웠고.. 왜 그렇게 동작하는지 이해가 안갔던 이슈다.

상황은 다음과 같다.
1.parent.html 에서 child.html 을 오픈 함
2.child.html 은 특정 동작을 취하면 parent.html에 저장된 window.setAction()호출
3.window.setAction( jSonData ) 와 같이 인자로 오브젝트 데이터를 전달하게 된다.
4.전달된 데이터는 전역 변수( 해당 스코프 안에서 ) parent.html 에서 저장하고 있다가. 특정 동작이 실행되면 ajax로 백엔드에 전달

언뜻보면 간단한 흐름을 가진 구조다. 하지만. 3번과 4번에서 IE8&9에서 문제가 발생한다. 즉 jsonData가 전달 당시에는 제대로 전달이 되는것 같지만, ( 디버그로 확인해보면 전달 당시에는 정상적인 값이 출력된다. ) 사용하려고 하면 null 도 아닌 null같은 쓰레기 값이 들어가 있어서 그 동작은 정상적으로 수행되지 않는다.

문제를 좀 객관화 하자면 IE 8&9에서는 부모페이지와 자식 페이지 상의 전역함수로 호출할경우 파라미터에 복잡한 JSON형태의 데이터가 들어가면 해당 데이터를 직접 저장하는게 아닌. 데이터가 생성되었을때 기준으로 shallow copy를 해오는것 같다. ( 이부분이 맞는지는 사실 정확히 모르겠다.. 자료를 찾아봐도 없다. )

이상황에서 자식창이 종료가 되면 shallow copy된 데이터도 같이 날아가버리는 현상이 발생한다.

문제에서 사용했던 data는 아래와 같다.

"data":[{
  "key1":"value",
  "key2":"value",
  "keyList":[{
    "key3":"value",
    "key4":"value"
   }],
  "key5":"value"
  },
  {
  "key1":"value",
  "key2":"value",
  "keyList":[{
    "key3":"value",
    "key4":"value"
  }],
  "key5":"value"
 }];

아무런 문제가 없는 일반적으로 사용하는 이중 배열 형태의 데이터다. 단지 data[0].keyList 가 한번더 배열인형태로 좀 복잡할 수가 있지만 (?) 트리 형태의 구조를 표현할때는 저렇게 구조를 잡는게 맞다.

당연히 해당 데이터는 circular-reference 로 만들어진 것도 아니였다. 그래서 해당 문제를 해결 하기 위해 일단 문제를 단순화 했다.

위의 과정중에
3. window.setAction( jSonData ) 와 같이 인자로 오브젝트 데이터를 전달하게 된다.
jsonData 부분에 위에 명시했던 데이터를 객체 형식으로 저장해서 과정4번 과정까지 진행해봤다. ( 즉 아래와 같이..)

var jsonData =[{  "key1":"value",
  "key2":"value",
  "keyList":[{
    "key3":"value",
    "key4":"value"
   }],
  "key5":"value"
  },
  {
  "key1":"value",
  "key2":"value",
  "keyList":[{
    "key3":"value",
    "key4":"value"
  }],
  "key5":"value"
 }];
window.setAction( jSonData );

정말로 신기한건 위와 같이 하면 문제가 해결 된다는 것이다.

하지만 실제로 웹서비스에서 저런 정적인 데이터는 불가능하므로, 다시 변수로 저장을 시도해봤다. 4번의 페이지에서 전달받았을 당시에는 IE8에서 디버깅을 해보면 문제없이 전달이 되므로.. 해당 변수 데이터를 클로저로 저장도 해보고. localStorage 에 저장도해보는 작업을 해본다.

하지만 결론은 모두 다 null도 아닌 쓰레기 값(?) 이 저장되며 여전히 4번 순서에서 오류가 났다..

그러다가 4번의 전달받은 데이터를 JSON.stringify( jsonData)로 해서 스트링으로 저장도 시도 해봤지만. 해당 데이터를 JSON.parse( )로 다시 JSON으로 만들때 circular reference 오류가 발생했다.
( circular reference가 나는 이유는.. 해당 데이터가 정상적이지 않기 때문에..)

정말 이리저리 삽질을 진행하다가 결국에는 문제를 해결했다.
아래는 해결한 방법이다.

var jsonData =[{  "key1":"value",
  "key2":"value",
  "keyList":[{
    "key3":"value",
    "key4":"value"
   }],
  "key5":"value"
  },
  {
  "key1":"value",
  "key2":"value",
  "keyList":[{
    "key3":"value",
    "key4":"value"
  }],
  "key5":"value"
 }];
jsonData = JSON.stringify( jsonData );
window.setAction( jSonData );

즉 자식 페이지에서 부모 페이지로 전달할때 JSON.stringify()로  스트링화 해서 전달한후 다시 JSON.parse() 해서 사용했더니 정보도 저장이 잘되었고 4번순서의 ajax 요청에도 정상적으로 활용할 수 있었다.

* 참고로 JSON관련 라이브러리는 jquery-json 을 사용했습니다. ( 그래서 문제없이 IE에서 JSON라이브러리를 사용가능)

뭔가 해결은 냈지만.. 원인을 정확하게 파악을 못해서 여전히 찝찝하다.

그 이후에 여러가지 방법으로 찾아봤는데.
https://support.microsoft.com/en-us/kb/2711084
위와 같은 내용이 존재한다. 요약하자면

IE 8에서는 윈도우창을 열었다 닫을때 참조하는 순환참조형태의 배열이 있다면 메모리 누수현상이 발생함” 이다.

물론 내가 만든 저 배열의 순환참조는 없었지만. IE 8에서 메모리 누수 현상이 있기때문에 내가 만든 패턴도 저 이슈에 걸렸다고 생각이되는데. 정확한 이해가 되지 않는데 다시 말하자면 나는 순환참조 배열이 아니다..

결국 의문점이 더 해소가 되지 않아서 더 찾아봤다. IE 에서 메모리 누수현상은 꾸준히 지적되어왔으니 내가 겪은 이슈도 분명히 있을것이라 생각하면서..
여러 검색 끝에 아래와 같이 결과물이 나왔다. (  MSDN..)

https://msdn.microsoft.com/en-us/library/bb250448(v=vs.85).aspx
해당 글에는 공식적으로 메모리 누수 패턴에 대해 설명하고 있다.

1.Circular References : 순환참조
2.Closures: 클로져
3.Cross-Page Leaks: 크로스 페이지 누수
4.Pseudo-Leaks : 슈도 누수(?)

드디어 찾았다. 3번째 크로스 페이지 누수다.

원문은 다음과 같다.

Cross-page leaks are often very small leaks of internal book-keeping objects as you move from site to site.

즉 사이트에서 사이트간의 이동 할때 내부적으로 저장된 객체해서 메모리 누수가 종종 발생한다고 한다.  이것을 스트링으로 저장하고 활용했기때문에 해결 가능했던 것이고 IE 8&9에서는 해당 이슈가 지적되며 개발자가 이런 객체로 저장하고 활용하는것을 어느정도 방어적으로 코드를 작성해야 한다고 나와있다.

많이 돌아와서.. 결국 이슈를 해결하고 원인도 알았다. ( 사실 이 포스팅을 준비하면서 더 찾아보다가여기까지 결론에 왔다.. 원래는 “~~해서 해결했다. 그래도 모르겠다. ” 였는데..)

한줄로 요약하자

IE 8&9 에서 사이트간 이동할때 객체형태의 데이터를 전달할때는 신중해야한다. (메모리누수 현상 발생할수도 있음 )

추가 : 포스팅 하고 해당 페이지의 3번째 이슈에 대한 상세 설명을 보면 DOM과 객체간의 이슈를 중점적으로 다루고 있다. 다만 내  이슈의 경우에는 자식창이 종료되면서 자식창이 가지고 있던 객체가 가비지 콜렉터에 의해 지워지면서 발생하는 이슈인것 같다.

이놈의 IE8 은 제발 없어져야 (.. ) 할 브라우저이다.

웹개발시에 이미지가  base64 encode되어서 들어가는 경우도 사실상 존재하긴한다.

(물론.. 절대경로 형태로 특정 이미지를 load하는게 더 좋은 방법이다. )

금년도 진행했던 프로젝트에서 텍스트 에디터로 summernote 라는 오픈소스를 사용했는데. ( http://summernote.org/  ) 다른 텍스트 에디터에 비해 최신 브라우저 지원이 잘되어있으며, bower  와 같은 도구도 지원하고 ui도 필요한것만 있어서 아주 유용하게 사용했다. (라이센스도 MIT이고.)

다만 이미지 업로드를 붙히는 과정에서. 여력이 안되서. 초기버전에는 summernote에서 지원하는 base64 encode 방식으로 이미지 삽입 기능을 사용했는데.

해당 기능을 사용하면 아래와 같이 HTML에 삽입이 된다.

<img style=”width: 275px;” src=”data:image/jpeg;base64,/9j/…..M0gH//2Q==” data-filename=”3.jpg”>

물론 간단한 이미지를 올리고 표시하는 경우에는 별도의 이미지 업로드 서버가 없이 사용할 수 있어, 상당히 유용한데.

문제는 이 데이터가 증가하면 DB가 감당하기도 어렵고, 조회 할때 너무 많은 데이터를 불러와서 API형태의 웹페이지에서는 그렇게 좋은 방법 같지는 않다.

게다가 여기서 문제가 발생했다.

QA를 통해 IE8에서 해당 이미지가 안보인다고 이슈라이징이 되었는데..

문제는 내 개발 PC 는 IE10이고. 개발자도구로 IE8로 렌더링/브라우저 모드를 변경해도 해당 이슈는 재현되지 않았다.

그래서 여러방면으로 찾아본 결과 아래의 글을 찾기에 이른다.

http://stackoverflow.com/questions/10159500/internet-explorer-and-base64-image-display

즉 IE8 에서는 32KB이상의 base64 encode 이미지를 지원 하지 않는 다는 것이다.

base64이미지를 사용하려면 32KB보다 낮은 이미지를 사용해야 하는데 사실상 안전성을 위해 사용하지 않는 편이 더 좋은것 같다. (급할땐 어쩔수 없지만..)

이후에 해당 기능은 별도의 이미지 서버에 올려서 URL을 리턴받는 방식으로 개발 교체 되었고, 지금은 문제가 발생하지 않는다..(하지만 이미이전에 만들어놓은 데이터가 속을 썪이고.. 있다.. )

만약 base64 인코딩된 이미지로 HTML에 삽입해서 페이지를 개발했는데 IE8에서 이슈가 발생한다면 빨리 이미지업로드 서버구축후 ( 아니면 오픈된 다른것을 사용하던가. ) 해당기능은 교체해야 할 것이다.