블로그

홍정모

최적의 프로그래밍 공부 방법

*같은 글의 브런치 링크MZ 세대를 위한 가장 효율적인 프로그래밍 공부 순서 요약- 문법보다 활용- 뭘 하든 생각하는 방법부터지금 프로그래밍 공부를 시작하거나 하고 있는 분들은 정말로 한 분 한 분이 소중합니다. 누구나 얼마든지 무럭무럭 자라나서 창조성을 꽃피울 수 있는 잠재력을 가지고 있음에도 불구하고 C언어 문법 공부로 대표되는 옛날 방식으로 지쳐버리는 것을 보는 것은 안타깝습니다.​오프라인/온라인에서 오랜시간 동안 다양한 과목들을 다양한 학생들에게 가르치면서 프로그래밍 교육에서 고려해야할 점들을 정리해봤습니다.​1. 흥미를 끌고 매 단계마다 재미를 느낄 수 있어야 합니다. 지루함을 억지로 참게하면 안되고 짧은 템포로 강한 집중력을 유도해야 합니다.​2. 왜 필요한지를 먼저 알려줘야 합니다. 예전에는 그냥 알아두면 나중에 도움된다며 일단 압박하며 가르쳐야했던 내용들도 다양한 응용 분야가 내 미래에 직결된다는 것을 미리 알게 되면 강한 의지를 보입니다.​3. 클릭만 유도하는 미디어에 지쳐가는 새싹들에게 수명이 짧고 단편적인 기술이 아니라 생각하는 방법 자체를 배울 수 있는 기회를 제공해야 합니다.​여기에 맞춰 가장 효율적인 프로그래밍 공부 방법을 정리해봤습니다.​1. 안정적인 초중고 교육은 인생 자체를 지탱하는 뿌리가 됩니다. 이 시기에는 컴퓨터로 인해 바뀌어가는 인류의 미래에 대해 호기심을 갖는 정도면 충분합니다. 타의에 의한 강압적인 선행학습은 권장하지 않습니다.​2. 프로그래밍 입문 초반부터 다양한 응용 분야에 대해 가볍게 체험을 해보는 것을 권장합니다. 자신의 가능성에 미리부터 선을 긋고 특정 분야에 대해 단편적인 지식만을 습득하는 방식은 미래의 나에게 족쇄를 채우는 행위일 뿐입니다. 프로그래밍 언어로는 파이썬을 추천합니다. C언어와 달리 소소한 불편함이 없고 분야별로 사용하기 쉬운 패키지들이 미리 준비되어 있어서 빠르게 다양한 체험을 할 수 있습니다. 이 단계에서 주의해야할 점은 쉬운 것일수록 스스로 해결할 수 있도록 올바르게 지도받아야 합니다. 나의 두뇌가 크게 성장할 수 있는 기회를 강탈당하지 않도록 주의하세요.​3. C/C++언어를 최소한으로 공부합니다. 딱 자료구조 공부에 필요한 만큼만 공부하시면 됩니다. C/C++ 문법을 깊게 들어가는 것은 알고리즘 공부 뒤에 자신이 선택한 응용 분야에서 필요하다면 그때 하시면 됩니다. 한 언어를 공부한 후에 다른 언어를 공부하는 것은 쉽구나 하는 체험도 이 단계에서 거쳐가야겠지요.​4. 프로그래밍 연습으로써의 자료구조 공부를 진행합니다. 우리의 목표는 "생각하는 방법 = 알고리즘"이지만 프로그래밍 연습이 부족한 상태에서는 반쪽짜리 공부가 되어버릴 수도 있습니다. 생각하는 방법을 터득하면서 동시에 구현까지 할 수 있으려면 약간의 프로그래밍 연습이 필요합니다. 그렇다고 해서 "C/C++ 문법 공부"를 "프로그래밍 연습"으로 착각하면 안되기 때문에 문법은 최소로 줄이고 자료구조를 공부하는 것을 추천합니다. 파이썬으로 다양한 응용 분야를 체험해봤기 때문에 자료구조와 알고리즘의 추상적인 개념들도 필요성을 느끼고 하나씩 내것으로 만들어나갈 수 있습니다. 파이썬으로 아주 기초적인 문제풀이를 해봤다면 더 좋습니다.​5. 알고리즘 공부를 시작합니다. 보다 구체적으로는 인터넷에 답이 없는 문제도 해결할 수 있는 능력을 갖추는 것입니다. 어떻게 공부해야할까요? 이미 앞에서 쉬운 것부터 스스로 해결하는 습관을 갖추셨다면 약간의 훈련만으로 빠르게 성장하실 수 있습니다. 이 단계에서 주의해야할 점은 코딩테스트 통과를 위한 문제 풀이와 알고리즘 공부를 헷갈리면 안됩니다. 쉬운 것부터 스스로 해결해온 순간들이 모여서 이때부터 화려하게 꽃 피우기 시작합니다. 알고리즘 공부는 Java로 하는 것도 괜찮습니다. 저는 C->C++로 흐름이 자연스럽게 연결될 수 있다는 점에서 C++을 추천합니다. 앞에서 이미 한 번 경험해봤듯이 C++ 후에 자바를 공부하는 것은 빠르게 하실 수 있습니다. 다만, 전문 영역으로써 깊게 언어를 파고드는 것은 추가적인 노력이 필요합니다.​6. 코딩 테스트 문제 풀이를 천천히 시작합니다. 알고리즘에서 터들한 내용들로부터 직결되는 문제들부터 몇 개만 스스로 풀어보며 감을 잡으면 문법 공부 직후에 바로 문제풀이 시작한 사람들보다 오히려 진행 속도가 훨씬 빠를겁니다. 문제풀이는 일찍 시작하고 꾸준히 하는 것을 추천합니다. 대신에 이제부터는 전문/응용 분야와 병행해야 합니다.​7. 전문/응용 분야 공부를 시작하면서 자유와 창의성을 발휘해보세요. 웹을 HTML 사용법 익히는 정도로 생각하는 경우도 있는데 저는 웹 프로그래밍도 고도로 전문화된 응용 분야로 봅니다. 웹, 앱, 서버, 게임, AI, 비전 등의 다양한 분야가 여러분들을 애타게 기다리고 있습니다. 특정 언어의 문법을 깊이 파고 들어가는 공부도 이때 시작하시면 되는데 복잡한 문법도 이런 문법이 왜 필요한지를 깨달으면 쉽게 이해가 되기 때문에 훨씬 수월할겁니다.​당연히 저도 제한된 경험을 가지고 있는 개인이며 제가 제시한 로드맵이 모두에게 정답은 아닐 수도 있습니다. 그러나 앞으로 고도화된 현대사회에서 평생 직장이란 개념 없이 오랜 기간동안 경력을 이어나가야 하는 MZ 세대가 효율적이면서도 미래지향적인 공부를 해나가는 데에 약간의 도움이라도 되기를 바랍니다.​2023년 1월 17일​홍정모 드림

프로그래밍 언어프로그래밍공부순서프로그래머알고리즘문제풀이자료구조코딩테스트웹프로그래밍프로그래밍공부홍정모

Jason

파이썬 왈러스 연산자 소개(필요성, 사용 예시)

이번 글에서는 왈러스 연산자에 대해 알아보겠습니다.왈러스 연산자는 아무래도 새로운 기능을 위한 개념이라기 보다는 짧고 직관적인 코드 작성에 사용되는 개념이다보니 직접 예제를 보며 설명하겠습니다.왈러스 연산자는 비교적 최근인 3.8 버전에서 등장한 개념입니다.한 줄에서 변수에 값을 할당하면서 동시에 이 값을 표현식의 일부로 사용할 수 있습니다.바다코끼리 연산자를 통해 파이썬에서 할당 표현식을 가능하게 합니다.여러분이 오랜만에 소비를 좀 하려고 합니다. 우선 그래픽 카드도 좀 사고 싶고,,, 그 다음 순위로 책(2권 사야됨), 그 다음 순위로 키보드, 그 다음 순위로 만년필을 선호한다고 가정하겠습니다.이제 온라인 쇼핑몰 속을 돌아다니며 현재 예산에서 무엇을 살 수 있을 지 봅니다!예산 내에서 그래픽 카드를 살 수 있으면 사고, 아니면 책 2권 값을 낼 수 있는 지 확인합니다. 그래도 안 되면 순서대로 키보드, 만년필을 살 수 있는지 확인해야 합니다.능숙한 프로그래머인 여러분들은 이정도는 파이썬으로 자동화하실 수 있죠?my_budget = 1000000 gift_value = { # 그래픽 카드는 품절이랍니다 'gc': 1300000, 'book': 50000, 'keyboard': 55000, 'pen': 80000 } # 99999999 정도면 품절 상품도 구매할 수 있다고 칩시다. value = gift_value.get('gc', 99999999) if value <= my_budget: print('그래픽카드 구매') else: value = gift_value.get('book', 99999999) if value*2 <= my_budget: print('책 주문!') else: value = gift_value.get('keyboard', 99999999) if value <= my_budget: print('키보드 구매') else: value = gift_value.get('pen', 99999999) if value <= my_budget: print('만년필 구매') else: print('살 수 있는 게 없습니다.') print(f'{my_budget}에서 {value}만큼 사용하셨습니다.')의도대로 동작하지만;; 너무 복잡해보이는 코드입니다. 제가 코드를 잘못 짰다고요?elif 사용을 통해 직관적으로 보이게 만들 수 있지만, 그렇게 쉽게 줄여지지 않습니다. 항상 동일 환경 조건에서 비교를 하는 것이 아니며(book 같은 경우에는 *2 후 비교) 각 상품마다 나오는 메시지가 다르기 때문입니다.이제 왈러스 연산자가 나올 시간입니다. 이 코드에 왈러스 연산자를 적용해보겠습니다.my_budget = 1000000 gift_value = { # 그래픽 카드는 품절이랍니다 'gc': 1300000, 'book': 50000, 'keyboard': 55000, 'pen': 80000 } if (value := gift_value.get('gc', 99999999)) <= my_budget: print('그래픽카드 구매') elif (value := gift_value.get('book', 99999999) * 2) <= my_budget: print('책 주문!') elif (value := gift_value.get('keyboard', 99999999)) <= my_budget: print('키보드 구매') elif (value := gift_value.get('pen', 99999999)) <= my_budget: print('만년필 구매') else: print('살 수 있는 게 없습니다.') print(f'{my_budget}에서 {value}만큼 사용하셨습니다')위아래 코드의 차이가 잘 느껴지셨으면 좋겠습니다.지금 본 사례처럼 왈러스 연산자를 사용하면 코드를 더 직관적이게 만들 수 있습니다.조건문 내에서 값을 할당하고 바로 검사, 블록 안밖에서 사용까지 할 수 있으니 정말 편리하다고 느낍니다.다른 사용 예시를 보며 마무리하겠습니다.# 입력값을 받아서 검사하고 처리 if (n := int(input("Enter a number: "))) > 10: print("10보다 큰 수를 입력했군")# 튜플 언패킹을 사용한 예 a, b = (1, 2) print(a, b) # 출력: 1 2 # 튜플 타입에서 왈러스 연산자를 사용하려면 반드시 명시적으로 괄호를 해주거나 따로 언패킹, 패킹해야 됩니다. (a := 1, b := 2) print(a, b) # 출력: 1 2 원문: https://pinstella.com/writer/articles/7

프로그래밍 언어파이썬pythonwalruscleancode

[프로그래밍 언어의 고민] JAVA와 Python중 언어 선택하기

개발자가 되기에 앞써  나는 비전공자이였기에, 혼자서하기에 많은 어려움이 있다. 처음 접하게되는 접근성의 어려움, 동기가 없이 혼자 시작해야함의 외로움, 남들보다 늦게 시작하는 불안감등 여러 어려움들이 있겠지만,  그중 내가 가장 크게 느끼는 어려운고민은  지금 내가 하고 공부하고 있는 개발이 옳은 길일까? 에 대한 의문점이 였다.  분명 이 의문점을 해결하기에는 온라인커뮤니티로도 한계가 있으며,  양산형적인(?) 학원 같은 곳도 형식적일것 같아,  최근에 알게된 개발자 훈련캠프를 알게되어 지원하였고 운이 좋게 최종테스트까지 다달았다.    하지만, 결국 시간이 턱없이 부족하여 떨어졌다.  떨어진 이유야 여러가지가 있겠지만,(+실력이 부족한것도) 익숙하지 않았던 JAVA 로 시험을 본게 아쉬웠다. 물론 최종테스트때 java언어만 국한되어 있다보니,  더 충분히 연습했어야 했는데, 그렇지 못한점도 있지만,  어쨌든 java라는 언어는 오래되기도 했고, 대기업 및 여러 국내기업에서 많이 사용하고 있는 언어다 보니,  지금이라도 익히면 도움이 될까 하고 공부하였었다.    하지만, 떨어지고 나서야 다시한번 내가 사용할 언어에 대해 되돌아보는 시간을 가지게 되었다. 나는 원래 Python언어로 개발공부를 시작했기에, 과연 JAVA로 바꾸는게 맞는지에 대한 의문이였다. (즉, 이후부터는 필자의 개인적인 의견이 많이 들어감을 참고바람)   가장 먼저 확인한 것은 전망이였다.  확인해본 방법은 아래와 같다.  1.티오베(프로그래밍순위사이트) 1위. Python,   2위. C언어   ,3위. Java 2. 구글트랜드검색 파란색: python , 빨간색 : java 3. 레드몽크(프로그래밍 순위사이트) 2위 : python,   3위 : java    등 그외에도 여러 사이트를 참조해봤지만, 그래도 윗내용은 믿고 맡길수 있는 사이트들이다. 물론, 티오베는 세계의 숙련된 엔지니어, 교육과정등 공급 업체의 수를 기반으로 프로그래밍 언어의 인기도 중심이고, 구글 트랜드검색은 경우의 수가 너무 많으며,  레드몽크도 GitHub와 Stack Overflow를 참고하여 데이터를 제공한다.    물론, 위자료는 세계적인 데이터로, 대한민국에서 개발자로 취업을 할려면 국내에서는 대부분의 대기업들은 Java언어를 사용하고 있어 지금 당장 대기업에 취업하고 싶다면 java의 언어를 선택하는게 좋다.  하지만, 좀더 멀리 보자면 전체적으로 비중이 커져가고 있는 python을 한번 봐보자.   이미 구글에서는 C++과 python을 백엔드로 사용하고 있고,  가장 대표적인 python어플로는 인스타그램이 있다.  그리고 OTT 시장의 (Netflix)넥플릭스도 파이썬으로 서비스를 관리하고 있으며,  클라우드 서비스 (Dropbox)드롭박스도 파이썬으로 개발하였다.  국내기업에서는 요기요 서비스가 파이썬으로 개발되는걸로 알고 있다.    게다가 국내 기업에서 개발자 채용테스트로  코딩테스트를 많이 보는데, python언어도 포함되어 점점 사용범위가 확대되어가고 있음을 알 수 있다. 현재는 AI(인공지능)와 데이터엔지니어부분에서 활용도가 점점 넓어지고 있는데,  좀더 직관적으로 보자면 자동차의 자율주행이나, 드론, 선박등 모빌리티 업계에 적용되고 있고,  또, 종종 보이는 서빙로봇과 같이 로봇에서도 많이 사용하는 언어이기에  이쪽으로 관심이 있다면, python언어  선택해볼만하다.    안드로이드때문에 앱부분은 java의 언어가 더 막강하지만,  안드로이드의 내장되어있는 기능을 사용하지 않는 플랫폼이나, 커뮤니티 앱일 경우  하이브리드로 만들기 때문에 다른 언어도 사용하여 만들기 가능하다. (웹도 마찬가지) --------------------------------------------------------------------------------------------------------------- 마지막으로 정리를 해보자면,  어느새부턴가 사람이름 세글자가 한자가 아닌 순 한글로된 이름으로  바뀌기 시작했다.  아직, 한자로된 이름을 가진 사람들이 더 많지만, 앞으로 태어날 아이들의 이름이 한자로된 이름이 계속 많을거라곤 장담하기 어렵다. 상대적으로 한자가 어렵다보니, 점점 아는 사람이 적어지고 한글이 편하기 때문일 것이다.  그렇다고 한자이름이 잘못되거나 없애야한다는 뜻은 아니다.  시대적흐름이 만들고 있을뿐..    java와 python도 비슷하다고 본다.  상대적으로 java보다는 python언어가 배우기 쉽다. 사용하기도 편리하다.  그리고 세계적으로 python을 선호하는 사람들이 많아지고 있다. 코딩언어도 결국 언어이다 보니  이건 소통하는 언어가 갖는 공통적인 습성이 아닐까싶다.    난 다시 python으로 돌아가 공부를 시작하고자 한다.                                

프로그래밍 언어진로javapython내생각언어공부고민

Devvy

Java의 실행원리 Deep Dive

Java는 다양한 운영체제에서 동일한 소스코드를 실행할 수 있는 "write once, run anywhere"의 철학을 지닌 프로그래밍 언어입니다. 국내에서 가장 활발히 사용되는 언어이며 제가 현업에서도 주로 사용하는 언어입니다. 이번 포스팅을 통해서 자바가 실행되는 원리에 대해 살펴보겠습니다. 블로그 원본 링크: https://code-run.tistory.com/61 프로그래밍 언어가 특정 운영체제 위에서 실행되기 위해서는 해당 운영체제가 이해할 수 있도록 코드가 작성돼야 합니다. 하지만 자바 개발을 하신 분들은 동일한. java 파일을 맥 OS, 윈도우 또는 Linux에서 실행한 경험이 있으실 겁니다. 정확히는 javac(자바 컴파일러)에 의해 컴파일된 .class 코드가 동일하더라도 해당 코드는 서로 다른 운영체제 위에서 실행될 수 있습니다. 이는 JVM 내부의 interpreter가 운영체제가 이해할 수 있는 코드로 변환해 주기 때문입니다. 즉 java는 운영체제가 이해할 수 있는 코드를 작성하는 책임을 프로그래머로부터 JVM으로 전이한 것으로 볼 수 있습니다. 운영체제별로 다운로드 받을 Java가 구분됨JDK, JRE, JVMJava 프로그램을 실행하기 위해서는 보통 JDK를 다운로드합니다. JDK와 항상 함께 등장하는 JRE 그리고 위에서 소개한 JVM에 대해 알아보겠습니다. JVM은 Java의 .class 파일이 실행될 수 있는 환경입니다. .class 파일의 bytecode를 host 운영체제 위에서 실행될 수 있는 환경을 제공합니다. JRE는 Java Runtime Environment의 약자로 자바 프로그램이 실행될 수 있는 최소환의 환경입니다. JRE는 JVM뿐 아니라 java 프로그램을 실행시키는데 필요한 라이브러리와 소스를 포함합니다. JDK는 Java Development Kit의 약자로 JRE를 포함합니다. 즉 JDK는 JRE와 JVM을 모두 포함하는 구조입니다. JDK는 javac, debugger 등 개발을 위한 도구를 포함합니다. JRE librariesJdk 설치와 함께 javac 등 설치Java의 실행 원리 .java 파일의 실행 흐름다음으로는 우리가 작성한 .java 파일이 어떻게 동작하는지 살펴보겠습니다. 우리가 작성한 .java 파일은 javac에 의해 .class 파일로 컴파일됩니다. 컴파일된 .class 파일은 JVM의 class loader에 의해 JVM의 메모리 영역에 로딩됩니다. JVM 메모리에 로딩된 후 execution engine의 interpreter에 의해 코드가 운영체제가 이해할 수 있는 기계어로 변환되고 이는 운영체제의 적절한 함수를 호출하여 필요한 로직을 수행합니다. 그럼 컴파일된 .class 파일이 어떻게 JVM 메모리에 로드되는지 상세히 살펴보겠습니다. Class Loader Subsystem Class loader subsystem의 주목적은 자바 프로그램을 실행시키기 위해 필요한 class를 찾아서 JVM의 메모리에 로드하고 연결(link) 하기 위함입니다. 필요한 class를 로드하고 연결하는 것 이외에 class variable을 초기화하는 역할도 수행합니다.Class loader subsystemLoad (Class Loaders) Java 프로그램 실행에 필요한 class를 jvm에 로드하기 위해서 class loader를 활용합니다. Class loader는 다음과 같이 목적에 맞게 역할이 나뉘어있습니다. Bootstrap class loader: JVM이 실행될 때 해당 java 프로그램 실행에 필요한 기본적인 class들을 로드합니다(rt.jar 파일 내의 java.lang 등). Extension class loader: Extension class들을 로드합니다(주로 jre/lib/ext에 위치). Extension class는 JDK가 추가적으로 제공하는 라이브러리입니다. Application class loader: classpath에 설정된 class를 로드합니다. 프로그래머는 실행시키고자 하는 java 프로그램의 classpath를 명시할 수 있습니다. // classpath를 직접 명시하는 방법 java -cp /path/to/classes:/path/to/jarfile MyMainClass java -classpath /path/to/classes:/path/to/jarfile MyMainClass // environment variable를 설정해서 classpath를 명시하는 방법 export CLASSPATH=/path/to/classes:/path/to/jarfile // system variable을 설정해서 classpath를 명시하는 방법 java -Djava.class.path=/path/to/classes:/path/to/jarfile MyMainClassLink Link 단계에서는 .class 파일 내의 symbolic references를 실제 메모리 주소로 변환하는 작업을 수행합니다. 단계별로 다음과 같은 작업을 수행합니다. Verify: .class 파일이 java 스펙에 맞는지 검증합니다. Bytecode format, version number 등을 확인하는 단계입니다. Prepare: 클래스와 static variable을 위한 메모리를 할당합니다. 중요한 점은 static variable이 default 값으로 초기화된다는 점입니다. 예를 들어 boolean 타입의 static 변수를 true로 설정하더라도 prepare 단계에서는 해당 변수는 false로 초기화됩니다. Resolve: symbolic reference를 실제 메모리 주소로 변환합니다.Symbolic reference란 우리가 코드를 작성하면서 사용한 class, field, method의 이름을 지칭합니다. Resolve 단계는 class, field, method 그리고 constant pool의 symbolic references를 실제 메모리 주소로 변환합니다. InitializeStatic initializer block을 실행합니다. 위 link의 prepare 단계에서는 static 변수가 default 값으로만 초기화됐지만 initialize 단계에서는 프로그래머가 지정한 값으로 static 변수가 설정됩니다. Initialize가 완료된 이후 main 메서드가 실행됩니다. Runtime Data Areas 다음으로는 JVM 메모리 구조에 대해 살펴보겠습니다.JVM runtime data area의 구조Method Area (Metaspace)Class level 정보를 저장하는 영역입니다. Class 정보, method 정보, static variable과 constant pool 정보를 저장합니다. Java 8부터는 기존의 method area의 한계를 극복하기 위해 method area가 제거되고 metaspace가 도입됐습니다. 기존의 method area의 경우 실행하고자 하는 java 프로그램에 클래스의 수가 너무 많을 때 "java.lang.OutOfMemoryError: PermGenspace" 에러를 발생할 확률이 컸습니다. 이는 method area가 heap의 일부 영역이었고 JVM에 할당된 메모리에 의해 최대 크기가 제한됐기 때문입니다. Metaspace는 JVM에 할당된 메모리가 아닌 system의 native 메모리를 활용하기 때문에 system의 가용 메모리에 제한을 받습니다. 따라서 method area를 활용하는 것보다 OutOfMemoryError가 발생할 확률이 낮아졌습니다. HeapRuntime에 생성된 object 또는 array를 저장하는 메모리 영역입니다. 모든 스레드에 의해 공유되는 영역으로 JVM 생성 시 할당됩니다. 자바 프로그램을 개발하면서 가장 많이 신경 쓰는 메모리 영역이기도 합니다. Managed 언어인 java이지만 memory leak이 발생할 수 있기 때문에 개발자는 사용하지 않는 객체의 참조가 정상적으로 해제되는지 신경 써야 합니다. 중요한 만큼 heap의 구조에 대해 상세히 살펴보겠습니다.VisualVM을 활용한 heap 분석Java의 heap 영역은 young과 old 영역으로 구분됩니다. Young은 말 그대로 최근에 생성된 객체들이 위치하는 영역이고 old 영역은 특정 threshold 이상의 기간 동안 살아남은 객체가 위치하는 영역입니다.  Young 영역은 또다시 eden, s0과 s1으로 구분됩니다. s0과 s1은 survivor의 약자입니다. 객체가 새로 생성될 때 해당 객체는 eden 영역에 할당됩니다. 그리고 eden 영역이 더 이상 객체를 저장할 수 없는 경우 minor gc(garbage collection)을 거쳐 s0 또는 s1의 영역으로 살아남은 객체를 이동시킵니다. 위 사진에서 보시면 s1에 저장된 객체가 없는 것을 확인할 수 있습니다. 다음 minor gc 때 eden과 s0 영역에서 살아남은 객체가 s1으로 이동하는데 이와 같은 플로우를 지니게 된 이유는 데이터 파편화(fragmentation)를 압축(compaction) 없이 해결하기 위해서입니다. 만약 s0과 s1이 동시에 사용된다면 gc에 의해 객체가 제거되면서 메모리 영역 중간중간이 비어 파편화 현상이 발생합니다. 이를 해결하기 위해서는 일정한 간격으로 압축이 필요하지만 JVM의 경우 s0 또는 s1 중 단 하나의 영역만 사용하기 때문에 별도의 압축과정이 필요하지 않습니다. Minor gc로 인해 s0과 eden에서 살아남은 객체가 s1으로 이동Young 영역에서 일정기간 이상 생존한 객체는 old 영역으로 승진(promote)됩니다. 만약 old 영역에 더 이상의 객체가 저장될 수 없는 경우 major gc(garbage collection) 수행합니다. 이때 application이 순간적으로 정지하는 stop the world 현상이 발생합니다. 사용하는 garbage collector의 특성에 따라 stop the world 현상이 상이할 수 있습니다. Heap과 관련돼서 중요한 설정으로는 -Xmx와 -Xms가 있습니다. Xmx 설정을 통해 heap의 최대 크기를 제한할 수 있고 Xms 설정을 통해 heap의 초기(최소) 크기를 설정할 수 있습니다. Xmx 값을 시스템 메모리보다 크게 설정하면 swap이 발생하여 시스템 전체적인 성능이 악화되거나 시스템이 다운될 수 있습니다. 따라서 Xmx값을 시스템 메모리보다 작게 설정하는 게 권고됩니다. 두 번째 권고 사항으로는 Xmx와 Xms 값을 동일하게 설정하는 것인데 이는 만약 두 설정값이 다른 경우 힙의 크기가 Xms에 도달했을 때 운영체제에게 추가 메모리를 요청함으로써 발생하는 오버헤드를 줄이기 위함입니다. 프로덕션 환경에서 운영해 보면 결국 JVM이 사용하는 메모리는 Xms를 넘어 Xmx를 향해 증가하기 때문에 Xms와 Xmx를 동일한 값으로 설정하는 것은 성능적인 관점에서 효율적일 수 있습니다.https://developer.jboss.org/thread/149559Why to set -Xms and -Xmx to the same value?| JBoss.org Content Archive (Read Only)In a production environment, if you monitor the GC data, you will notice that is a relatively short period of time (usually less than an hour), the JVM will eventually increase the heap size to the -Xmx setting. Each time the JVM increases the heap size itdeveloper.jboss.orgJava Stacks 메서드 실행 시 생성되는 function call frame을 저장하기 위해 사용됩니다. Function call frame에는 해당 메서드에서 생성된 지역 변수 등이 저장됩니다. Thread별로 stack 영역이 할당됩니다. 만약 이 영역에 너무 많은 데이터가 저장되는 경우 stack overflow error가 발생할 수 있습니다. 또한 JVM의 -Xss 옵션을 활용해서 stack의 최대 깊이를 제한할 수 있습니다. PC Registers Program counter을 저장하기 위해 사용되는 영역입니다. 특정 thread의 실행 위치를 표시하므로 각각의 thread별로 pc register가 생성됩니다. Native Method Stacks Thread에서 native method를 호출하는 경우, 즉 java 이외의 언어로 작성된 코드를 호출하는 경우 사용됩니다. Thread별로 생성됩니다. Execution Engine Execution engine은 JNI를 활용해 운영체제의 함수를 호출합니다. 이 과정에서 사용되는 각각의 컴포넌트에 대해 살펴보겠습니다. JNI(Java Native Interface)는 JVM에서 실행 중인 java 코드에서 다른 언어(C/C++)로 작성된 코드를 호출할 수 있도록 도와주는 프레임워크입니다. 자바의 기능만으로 수행할 수 없는 로직 또는 성능적인 측면에서 다른 언어를 사용하는 게 효율적일 때 사용됩니다. Execution engineInterpreter Bytecode를 읽어 native code(machin code)로 변환하는 역할을 담당합니다. 자주 실행되는 코드가 실행될 때마다 매번 interpreter에 의해 변환되면 비효율적입니다. 이러한 단점을 극복하기 위해 JVM은 JIT compiler을 활용합니다. JIT Compiler JIT은 just-in-time의 약자입니다. 즉 적절한 시기에 bytecode를 캐싱하고 최적화함으로써 자주 호출되는 코드가 interpreter에 의해 여러 번 변환되는 작업의 수를 줄일 수 있습니다. JIT compiler는 tiered compilation을 활용함으로써 단계별로 최적화하는 정도가 다릅니다. 현업에서 발생할 수 있는 문제 중 하나는 java 애플리케이션이 시작한 지 얼마 되지 않았을 때 코드가 충분히 캐싱 또는 최적화되지 않아 응답지연이 발생하는 점입니다. 이는 JVM warmup을 통해 해결할 수 있습니다. 카카오에서 JVM warmup을 통해 응답지연 현상을 어떻게 해결했는지 좋은 영상이 있어 공유드립니다. https://www.youtube.com/watch?v=CQi3SS2YspY&t=1sProfilerInterpreter에 의해 자주 변환되는 코드를 파악하는 데 사용됩니다. Garbage Collector 사용되지 않는 객체에 할당한 메모리를 해제하지 않으면 언젠가는 OutOfMemoryError에 의해 프로세스가 종료될 수 있습니다. 자바의 경우 참조되지 않는 객체에 할당된 메모리를 garbage collector을 활용해 해제합니다. 그럼 garbage collector은 어떻게 동작하는지 살펴보겠습니다. "Mark and Sweep"은 다양한 garbage collector들의 동작원리입니다. Mark 단계에서는 live 스레드에서 참조하는 객체들을 표시하고 sweep 단계에서 참조되지 않는 객체의 메모리를 해제합니다. Garbage collector의 특성에 따라 garbage collection 중에 애플리케이션이 동작하는 방식이 달라집니다. 다음으로는 어떤 garbage collector가 존재하는지 살펴보겠습니다. Serial GC Serial GC단일 스레드로 mark and sweep을 통해 garbage collection을 수행합니다. Parallel GC Parallel GCSerial collector와 동작원리는 유사하지만 여러 스레드를 활용해서 mark and sweep을 수행합니다. CMS(Concurrent Mark and Sweep) GC 애플리케이션의 중단 없이 mark and sweep이 가능한 garbage collector입니다. 애플리케이션 중단을 최소화하기 위해 사용됩니다. 물론 CMS라고 stop the world 현상이 없지는 않습니다. Initial mark 단계와 remark 단계에서는 stop the world 현상이 발생합니다.  CMS는 다음 순서로 동작합니다. 1. Initial mark: Old 영역의 참조되고 있는 객체를 표시합니다. 짧게나마 stop the world 현상이 발생할 수 있습니다. 2. Concurrent marking: 자바 애플리케이션 중단 없이 참조되는 객체들을 표시합니다. 3. Remark: concurrent marking 단계에서 놓친 참조되는 객체들을 표시합니다. Stop the world 현상이 발생할 수 있습니다. 4. Concurrent sweep: 참조되지 않는 객체의 메모리를 해제합니다. G1(Garbage First) GC G1 GCJava 9 이상부터는 기본 설정되는 GC로 큰 heap에서도 garbage collection에 소요되는 시간을 최소화하기 위해 개발된 garbage collector입니다. G1 GC는 heap을 작은 영역으로 나눠 각 영역에 대해 독립적인 garbage collection을 수행합니다. 여러 영역 중 garbage가 가장 많은 영역을 골라 우선적으로 garbage collection을 수행합니다. 추가로 G1 GC는 "Garbage-First Virtual Space"라는 자료구조를 활용해서 heap의 어떤 영역이 가장 많은 garbage를 가졌는지 추적합니다.  G1 GC는 다음 순서로 동작합니다. 1. Initial mark: 애플리케이션 중단 없이 현재 스레드에서 참조되고 있는 객체를 표시합니다. 2. Concurrent marking: Live  스레드로부터 참조되는 객체를 추가로 찾아 marking 하는 단계입니다. 3. Remark: 짧은 stop the world 현상이 발생할 수 있습니다. 이는 remark 단계에서 live 스레드로부터 참조되는 객체를 정확히 표시하기 위함입니다.4. Garbage collection: Heap에서 가장 많은 garbage를 가진 영역들에 대해 우선적으로 garbage collection을 수행합니다. 애플리케이션 중단 없이 수행됩니다. 5. Clean up: 파편화를 제거하기 위한 압축 등 garbage collection 이후 수행돼야 하는 작업을 수행합니다. 마무리 이번 포스팅을 통해 우리가 작성한 java가 어떻게 실행되고 java를 실행하는데 필요한 다양한 소프트웨어에 대해 살펴봤습니다. JVM은 자바뿐 아니라 Kotlin, Scala 등 다양한 언어의 실행환경이기 때문에 그 내부원리를 잘 이해하는 게 중요하다고 생각합니다. 

프로그래밍 언어JavaJVM

C++의 데이터 열거를 진행하는 방법에 대한 이야기

#include <iostream> using namespace std; /* const로 상수를 설정하다보면 */ const int SCISSORS = 1; const int ROCK = 2; const int PAPER = 3; /* 위에 작성된 것처럼 작성하기 마련이다. 하지만 의미 부여상으로 보면 저렇게 같은 성격을 가진 존재들끼리 하나로 묶는 개념이 필요하다. */ /* 그래서 나타난 개념이 바로 'ENUM'이다! */ enum ENUM_SPP { ENUM_SCISSORS = 1, ENUM_ROCK, ENUM_PAPER }; /* ENUM은 const에 비해 초기값을 설정하지 않아도 된다. (ENUM 과 const의 차이점) 그럼 ENUM 값은 지정을 하지 않을 경우 어떻게 되는가? 숫자를 지정 안하면 첫 값은 0부터 시작한다. (즉, ENUM_SCISSORS = 0; 이라는 의미이다.) 그 다음의 값들은 이전 값에 + 1이 진행된다. 여기서 처음 값을 정한다면? 그 다음 값들도 같이 이전 값에 + 1이 된 상태로 빌드가 된다. */ /* 그렇다면 여기서 const 와 ENUM의 명확한 쓰임새와 차이점에 대해 알아보자. 1. const 의 경우, 메모리에 저장될 때, 되지 않을때가 있다. 일반적으로 const는 빌드를 진행할 때, 메모리에 주소값이 지정되어 있지 않다. F5를 눌러 확인해보면 [식은 lvalue 또는 함수 지정자여야 합니다.]로 출력될 것이다. 하지만 int main() 안에서 auto a = &SCISSORS; 이런 경우, SCISSORS의 주소값을 auto a 에 넣어줬기에 메모리에 담겨 있는 모습을 확인할 수 있다. 이를 조금 심화적으로 다루어 보자면 int main() 밖(data 영역)에 선언한 const int ~~ 들은 메모리에 올라가지 않고 실행될 때, int main() 안에서 자신들이 쓰여진 부분에 자신들(변수)이 들어가는게 아니라 자신의 값(1,2,3)등이 바로 들어가는 경우가 생긴다. 또는 int main() 안(Stack 영역)에 선언한 const int ~~ 들은 stack 영역에 올라가서 동작 방식으 달라질 수 있다. 또는 int main() 밖(data 영역)에 선언한 const int ~~ 을 int main() 안에서 auto b = &ROCK; 처럼 선언한다면 이를 메모리에 할당하게 되는데, 이 방법은 위에서 알게된 방법과 다르게 메모리를 더 소모하는 방향으로 진행된다. (즉, 메모리의 과소모 = 낭비가 이루어질 수 있는 방법이다.) */ /* #이 붙은 개념 -> 전처리 지시문을 의미한다. 우리가 컴파일을 진행할 때, 1) 전처리 -> 2) 컴파일 -> 3) 링크 컴파일을 진행하기 전에 미리 컴파일 하기 쉽도록 거치는 단계 = 전처리 그럼 우리는 어디서 #을 사용하는 거지?! 우리는 CPP 파일을 만들 때, 항상 #include <iostream> 을 작성한다. iostream 의 내용을 전부 긁어서 여기에 붙여주세요!! 라는 의미로 받아들이면 된다. 위에서 간단한 예시로 알아본 결과 DEFINE_SCISSORS 로 작성된 부분을 1이라는 값으로 넣어서 진행해주세요!! 라는 의미로 쓰여진다고 보면 된다. */ #define DEFIME_SCISSORS 1 /* const와 ENUM은 우리가 정수만 사용했었다. 놀랍게도 #define은 정수도 출력할 수 있다. */ #define DEFIME_TEST cout << "HELLO, WORLD"<< endl; /* #define을 그렇게 추천하지 않는 이유가 있다고 한다..... 파일을 실행하면, 앞서 설명 했듯이 (우리가 컴파일을 진행할 때, 1) 전처리 -> 2) 컴파일 -> 3) 링크) 순서대로 진행이 된다. 그렇기에 전처리 단계에서 진행이 되는 #define을 디버깅해서 볼 때는, 결코 찾아볼 수 없다. 이유는 이미 컴파일을 진행할 당시 define에 정의한 변수들이 전부 define의 값으로 치환되어서 컴파일이 진행되었기에 이를 찾아볼 수 없는 것이다. 그렇기에 #define을 추천하지 않는 것이다.(물론 필요하고 적재적소인 부분에서는 사용하는 것이 맞다!) */ int main() { /* 그렇다면 여기서 ENUM에 대한 부분을 살펴보자 */ int input; if (input = ENUM_SCISSORS) { cout << "SCISSORS" << endl; } /* 위처럼 ENUM_SCISSORS 로 작성된 부분에 제대로 된 ENUM_SCISSORS의 값이 들어가게 된다. 이는 메모리를 낭비하는 일도 없으며 const로 선언한 data를 사용하는 방법보다 좋은 부분을 보여준다. 하지만 현업에서는 상황에 따라서 const를 사용하는 경우도 있다보니 이렇게 간단하게 개념을 익히고 가자. */ }

프로그래밍 언어학습일기

[인프런 워밍업 클럽 BE + ]람다식/스트림 추가 학습하기!

3일차 과제는 조사 과제로, 함수형 인터페이스/람다/스트림 등의 광범위한 키워드를 알아봐야 했다. 검색하면 할수록 부족한 내 자신이 느껴졌다😂. 람다식의 문법 체계와 스트림 API를 문서로만 보았을 때는 나름 할만한데? 라는 생각이 들다가도, 직접 코드를 접하면 이해가 빠릿하게 되지 않는다니... 역시 나는 보는 것 만으로는 50프로도 흡수를 못하는 것 같다. 직접 예제를 만들어보기에는 개념도 겨우 잡는 학생이 시험 문제를 낸다는 느낌이기에, 어떻게 효과적으로 코드 작성하는 걸 공부할 수 있을까? 라는 고민에 빠지다 문득 생각이 들었다. 람다식과 스트림이라는 개념 자체를 몰랐을 적, 프로그래머스에서 나는 몇 줄에 거쳐 해결한 문제를 누군가가 스트림으로 한 줄 만에 풀이를 끝내는 걸 본 기억이... 그래서 나도 그 기억에 따라 프로그래머스의 기초 문제를 람다식과 스트림 API을 통해 푸는 연습을 해보기로 했다!연습 범위는 lv0~lv1. 두 개념을 사용할 수 있는 문제들만 임의로 골라서 꾸준히 풀기!❗문제 전문이나 정답 코드는 작성하지 않는다. 어디까지나 개인 연습용이라 최고 효율적인 답을 기대하고 풀이하지 않습니다. 문제가 막힐 때, https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html 등의 문서 참조'다른 사람의 풀이' 보기!(최후 수단) 1.IntStream을 이런 방식으로도 사용할 수 있다는 생각이 미처 닿지 못해, 부끄럽게도 첫 문제부터 다른 사람의 풀이를 참고하였다. 이번 키워드 메서드를 한 번 보자.IntStream.range(0, strArr.length) .mapToObj(...) .toArray(...);IntStreamrange(n1, n2) - [n1,n2) 까지 순서대로 정렬된 연속된 값을 가진 IntStream 반환[n1,n2]의 경우에는 rangeClosed(n1, n2)를 사용한다.mapToObj(IntFunction<? extends U> mapper) - 스트림 요소에 주어진 함수를 적용한 결과로 구성된 객체 값 반환 정확성 테스트 결과는 위와 같다.이번 문제는 일반적인 반복문을 사용했을 때 압도적으로 빨랐다. 반복문 처리 하였을 때의 정확성 테스트 결과 이미지이다. 

프로그래밍 언어개인학습

코어자바스크립트 강의정리 - 1. 데이터 타입

1. 데이터 타입  자바스크립트 데이터 종류 (기본형, 참조형) 기본형 데이터 : 정적할당 참조형 데이터 : 동적할당 Why? 기본형 데이터의 할당 방식 var a = 1 이라고 하였을때 자바스크립트 내부적으로는 var a; a = 1; 로 처리 따라서 임의의 메모리 주소(1004) 에 (이름 : a, 값 : 없음) 저장 후 다른 임의의 메모리 주소(5000)에 데이터 1 을 저장. 그리고 메모리 주소 1004 의 값에 메모리 주소 5000을 저장하여  (이름 : a, 값 : @5000) 으로 만든다.   참조형 데이터의 할당방식 var obj= { a : 11,  b : 11} 이라고 하였을때 메모리주소 1004에 (이름 : obj, 값 : 없음) 저장, 임의의 메모리 주소 5000에  @7000~@70?? 까지의 메모리 주소 데이터 저장(배열이나 객체는 값이 여러가 들어가기 때문에 미리 공간을 확보해 둠) @7000 에 정적 할당 방식과 같이 (이름 : a , 값 : 없음) 저장, 임의의 메모리 주소 @5001에 데이터 11 저장. @7000 의 값을 @5001 로 저장. @7001 에 (이름 : b, 값 : @5001) 저장. @1004의 값에 @5000 저장.   결국 어떤 데이터를 저장할때 기본형이나 참조형이나 가장 작은 데이터의 단위(위의 예시에서 1, 11 과 같은 값)를 중복하지 않고 공유해서 가지고 있고, 그 주소를 참조한다. 그렇기 때문에 const obj 를 사용하여도 obj 내부의 값을 바꿀수 있는 것. 같은 원리로 var obj2 = obj ; obj2.a=99; 를 하고 나면 obj나 obj2나 @5000이 가리키고 있는 @7000~@70?? 의 값을 받아오기 때문에 obj.a 도 99의 값을 갖는다.   번외 : 그럼 왜 자바스크립트는 가장작은 데이터의 단위를 굳이 따로 저장할까? var a = 1을 하였을때 @1004 (이름 : a, 값 :1 ) 을 하는 것이 할당 속도면에서 더 효율적이지 않을까(장점1)? 라는 의문이 생길 수 있다. 그러나 큰 값이 여러번 저장될때 예를들어 "매우매우긴문자열" 이라는 문자열을 매번 직접 값을 저장하는 방식을 사용하면 하나의 문자열을 계속해서 참조하는 방식에 비해 메모리를 더 차지하게 된다(단점1). 심지어 값을 비교하는 작업이 있다면 매우 긴 문자열의 값을 매 , 우, 매, 우,  긴, 문, 자, 열 로 하나하나 비교해야 해서 하나의 메모리 주소값만 비교하는 방식에 비해 오래걸린다(단점2). 현재 자바스크립트가 사용하고 있는 방식은 값을 한번 할당할때는 느리지만(단점1), 비교에 비용이 들지 않는다(장점1). 또한 할당한 값이 여러군데에서 중복해서 사용될 때에 메모리의 낭비가 적다(장점2). 그렇기때문에 단점보다 장점이 많은 현 자바스크립트의 방식을 자바스크립트는 채택한 것이다.  

프로그래밍 언어자바스크립트

[삽질] 알고도 당하는 Optional의 함정

Java로 진행중인 개인 프로젝트에서 Optional을 요긴하게 쓰고 있다. Null을 사용하였다면 Null check를 일일이 확인하고 테스트하면서 애로사항이 생겼을텐데, Optional 타입을 쓰면서 Null에 대한 확인이 강제되다보니 타입 에러를 따라가서 고쳐주기만 하면 되어서 나름대로 만족하면서 코딩을 하고 있다. 다만 Optional에도 함정이 있었으니... 그렇잖아도 Optional 바르게 쓰기 등의 글들을 보면서 조심해야겠다고 생각하고 있었는데 읽었고 아는 내용인데도 실수하여 이렇게 글을 남기게 되었다. 문제의 코드를 소개하자면 다음과 같다. 이렇게 보면 뻔할 수도 있겠지만 많은 코드 사이에 이게 끼어 있었을 때는 너무 자연스러워서 눈에 띄지 않았던 것 같다. `catRepo`는 카테고리 Entity를 데이터베이스에 저장하는 Spring Data JPA의 Repository이다. // 안중요한 부분들 과감히 생략 @Annotations public class OscillatorService { private final CategoryRepository catRepo; public Category findOrSave(Category category) { return catRepo .findByRuleAndPeriodAndSparkType( category.getRule(), category.getPeriod(), category.getSparkType()) .orElse(catRepo.save(category)); } } 위 코드에서 잘못된 점은 바로 `Optional::orElse`이다. 뭔가 읽기에는 Entity를 찾아보고 Entity가 있으면 그걸 쓰고 없으면 새로 저장하고 쓰라는 것 같지만, 실제로는 `Optional::orElse` 안의 값은 Optional 안의 값에 상관없이 evaluation된다. 본인의 경우 역시 값을 찾았는데도 불구하고 `catRepo.save(category)`가 실행해서 오류가 발생하였다. 그러면 위를 해결해주려면 어떻게 하면 좋을까. `Optional::orElseGet`을 사용하여 다음과 같이 바꾸면 해결된다. // 안중요한 부분들 과감히 생략 @Annotations public class OscillatorService { private final CategoryRepository catRepo; public Category findOrSave(Category category) { return catRepo .findByRuleAndPeriodAndSparkType( category.getRule(), category.getPeriod(), category.getSparkType()) .orElseGet(() -> catRepo.save(category)); } } 꼭 side effect가 있거나 계산이 시간이 많이 걸리는 작업이 아니더라도 그냥 `Optional::orElse` 대신 `Optional::orElseGet`을 쓰는 것이 마음이 편한 것 같아서 앞으로는 기본적으로 `Optional::orElseGet`을 쓰기로 마음먹었다.

프로그래밍 언어Java

Mac codesign 및 실행 파일 변환 하는 Script

apple script 는 권한 문제가 있다 do sheel ..... with administrator privileges 권한문제 가 몬테레이에서 작동하지않는다. 해결이 안된다 sudo 를 암호 없이 실행하게 만들라 하는데 .. Automator 에 빠른실행에 스크립터로 넣으면 된다. 쉘 스크립터가 더나은것같지만 실행파일변환시 와일드카드처럼작동한다, ---------------------------------------------Apple Script---------------------------- on run {input, parameters} set getData to input set orgPath to POSIX path of (getData as text) set strPath to (alias getData as string) & "Contents:Macos:"     set mypath to alias strPath set {folder:Fo, package folder:Pa} to info for getData without size if Fo and not Pa then display dialog "😂선택한 항목은 폴더입니다 스크립터를 종료합니다😂" else if Fo and Pa then set p to POSIX path of ((choose file with prompt "😀실행파일로 변환할 파일을 선택하세요😀" of type {} default location mypath) as text) do shell script "xattr -cr " & quoted form of orgPath & "; codesign --force --deep --sign - " & quoted form of orgPath & "; chmod 577 " & quoted form of p else do shell script "chmod 577 " & quoted form of orgPath & "; xattr -cr " & quoted form of orgPath & "; codesign --force --deep --sign - " & quoted form of orgPath end if end run ---------------------------------------------Shell Script---------------------------- export HISTIGNORE='*sudo -S*' for f in "$@" do if [ -d "$f" ] ; then echo "YOURPASSWORD" |sudo -S -k xattr -cr "$f" echo "YOURPASSWORD" |sudo -S -k codesign --force --deep --sign - "$f" # space filename no process. Macos folder all file EXE for fileName in $(ls "$f/Contents/MacOS/"); do     echo "YOURPASSWORD" |sudo -S -k chmod 577 "$f/Contents/MacOS/$fileName" done else echo "YOURPASSWORD" |sudo -S -k chmod 577 "$f" fi done

프로그래밍 언어