스왑 공간과 관련된 링커 성능?
때때로 정적 메모리의 큰 덩어리를 사용하는 작은 C 프로그램으로 무언가를 조롱하는 것이 유용합니다.페도라 15로 변경한 후 프로그램을 컴파일하는 데 시간이 오래 걸린다는 것을 알게 되었습니다.우리는 30대 대 0.1대입니다.더 이상한 것은 ld(링커)가 CPU를 최대로 사용하고 있었고 사용 가능한 모든 메모리를 천천히 먹기 시작했다는 것입니다.약간의 조작 끝에 저는 이 새로운 문제와 스왑 파일의 크기 사이의 상관 관계를 찾을 수 있었습니다.다음은 이 토론의 목적을 위한 프로그램의 예입니다.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define M 1000000
#define GIANT_SIZE (200*M)
size_t g_arr[GIANT_SIZE];
int main( int argc, char **argv){
int i;
for(i = 0; i<10; i++){
printf("This should be zero: %d\n",g_arr[i]);
}
exit(1);
}
이 프로그램에는 약 200*8MB = 1.6의 선언된 크기를 가진 거대한 어레이가 있습니다.정적 메모리의 GB입니다.이 프로그램을 컴파일하는 데 너무 많은 시간이 걸립니다.
[me@bleh]$ time gcc HugeTest.c
real 0m12.954s
user 0m6.995s
sys 0m3.890s
[me@bleh]$
13s ~13 라인 C 프로그램의 경우!?그건 옳지 않아요.키 번호는 정적 메모리 공간의 크기입니다.총 스왑 공간보다 크면 즉시 다시 빠르게 컴파일이 시작됩니다.예를 들어 5.3이 있습니다.스왑 공간의 GB이므로 GIANT_SIZE를 (1000*M)으로 변경하면 다음 시간이 제공됩니다.
[me@bleh]$ time gcc HugeTest.c
real 0m0.087s
user 0m0.026s
sys 0m0.027s
아, 그게 더 좋아요!가정에서 사용하는 경우 스왑 공간이 마법의 숫자임을 더욱 확신시키기 위해 사용 가능한 스왑 공간을 19GB의 대용량으로 변경하고 (1000*M) 버전을 다시 컴파일해 보았습니다.
[me@bleh]$ ls -ali /extraswap
5986 -rw-r--r-- 1 root root 14680064000 Jul 26 15:01 /extraswap
[me@bleh]$ sudo swapon /extraswap
[me@bleh]$ time gcc HugeTest.c
real 4m28.089s
user 0m0.016s
sys 0m0.010s
그것은 심지어 4.5분이 지나도 완성되지 않았습니다!
링커가 여기서 뭔가 잘못하고 있는 것은 분명하지만, 프로그램을 다시 쓰거나 스왑 공간을 만지작거리는 것 외에는 이 문제를 해결하는 방법을 모르겠습니다.저는 해결책이 있는지, 아니면 제가 어떤 불가사의한 벌레를 우연히 발견했는지 알고 싶습니다.
그런데, 모든 프로그램은 모든 스왑 비즈니스와 관계없이 올바르게 컴파일되고 실행됩니다.
참고로 다음은 관련 정보일 수 있습니다.
[]$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 27027
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 1024
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
[]$ uname -r
2.6.40.6-0.fc15.x86_64
[]$ ld --version
GNU ld version 2.21.51.0.6-6.fc15 20110118
Copyright 2011 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.
[]$ gcc --version
gcc (GCC) 4.6.1 20110908 (Red Hat 4.6.1-9)
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[]$ cat /proc/meminfo
MemTotal: 3478272 kB
MemFree: 1749388 kB
Buffers: 16680 kB
Cached: 212028 kB
SwapCached: 368056 kB
Active: 489688 kB
Inactive: 942820 kB
Active(anon): 401340 kB
Inactive(anon): 803436 kB
Active(file): 88348 kB
Inactive(file): 139384 kB
Unevictable: 32 kB
Mlocked: 32 kB
SwapTotal: 19906552 kB
SwapFree: 17505120 kB
Dirty: 172 kB
Writeback: 0 kB
AnonPages: 914972 kB
Mapped: 60916 kB
Shmem: 1008 kB
Slab: 55248 kB
SReclaimable: 26720 kB
SUnreclaim: 28528 kB
KernelStack: 3608 kB
PageTables: 63344 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 21645688 kB
Committed_AS: 11208980 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 139336 kB
VmallocChunk: 34359520516 kB
HardwareCorrupted: 0 kB
AnonHugePages: 151552 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 730752 kB
DirectMap2M: 2807808 kB
TL;DR: c 프로그램의 (큰) 정적 메모리가 사용 가능한 스왑 공간보다 약간 적을 때, 링커는 프로그램을 연결하는 데 오랜 시간이 걸립니다.그러나 정적 공간이 사용 가능한 스왑 공간보다 약간 큰 경우에는 매우 빠릅니다.무슨 일이에요?
을 우분투에서 재생할 수 있습니다 (우분투 10.10 시수있다니습할재현이서를에템스(다▁i니있습ub▁this수▁on▁(▁to▁an▁able)GNU ld (GNU Binutils for Ubuntu) 2.20.51-system.20100908
), 그리고 저는 당신의 답을 알고 있다고 생각합니다.먼저, 몇 가지 방법론입니다.
소규모 VM(512MB RAM, 2GB 스왑)에서 이러한 현상이 발생하는 것을 확인한 후, 여기서 가장 쉬운 방법은 strackcc를 사용하여 모든 것이 엉망이 되었을 때 정확히 어떤 일이 일어나고 있는지 확인하는 것이라고 결정했습니다.
~# strace -f gcc swap.c
다음 항목이 켜졌습니다.
vfork() = 3589
[pid 3589] execve("/usr/lib/gcc/x86_64-linux-gnu/4.4.5/collect2", ["/usr/lib/gcc/x86_64-linux-gnu/4."..., "--build-id", "--eh-frame-hdr", "-m", "elf_x86_64", "--hash-style=gnu", "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2", "-o", "swap", "-z", "relro", "/usr/lib/gcc/x86_64-linux-gnu/4."..., "/usr/lib/gcc/x86_64-linux-gnu/4."..., "/usr/lib/gcc/x86_64-linux-gnu/4."..., "-L/usr/lib/gcc/x86_64-linux-gnu/"..., ...], [/* 26 vars */]) = 0
...
[pid 3589] vfork() = 3590
...
[pid 3590] execve("/usr/bin/ld", ["/usr/bin/ld", "--build-id", "--eh-frame-hdr", "-m", "elf_x86_64", "--hash-style=gnu", "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2", "-o", "swap", "-z", "relro", "/usr/lib/gcc/x86_64-linux-gnu/4."..., "/usr/lib/gcc/x86_64-linux-gnu/4."..., "/usr/lib/gcc/x86_64-linux-gnu/4."..., "-L/usr/lib/gcc/x86_64-linux-gnu/"..., ...], [/* 27 vars */]) = 0
...
[pid 3590] lseek(13, 4096, SEEK_SET) = 4096
[pid 3590] read(13, ".\4@\0\0\0\0\0>\4@\0\0\0\0\0N\4@\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096
[pid 3590] mmap(NULL, 1600004096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1771931000
<system comes to screeching halt>
우리가 의심했던 것처럼, 그것은 보기에, 우리가 의심했던 것처럼 보입니다.ld
실제로 익명으로 시도하고 있습니다.mmap
이 어레이의 전체 정적 메모리 공간(또는 전체 프로그램)은 프로그램의 나머지 부분이 너무 작기 때문에 구분하기 어렵습니다. 추가 4096에 모두 들어맞을 수 있습니다.
이 모든 것이 좋습니다. 하지만 시스템에서 사용 가능한 스왑을 초과할 때 이 기능이 작동하는 이유는 무엇입니까?swapoff
그리고 실행strace -f
다시...
[pid 3618] lseek(13, 4096, SEEK_SET) = 4096
[pid 3618] read(13, ".\4@\0\0\0\0\0>\4@\0\0\0\0\0N\4@\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096
[pid 3618] mmap(NULL, 1600004096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
[pid 3618] brk(0x60638000) = 0x1046000
[pid 3618] mmap(NULL, 1600135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
[pid 3618] mmap(NULL, 134217728, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0) = 0x7fd011864000
...
놀랄 것도 없이, ld는 지난 번에 시도했던 것과 동일한 작업을 수행한 것 같습니다. 전체 공간을 매핑하기 위해. 하지만 시스템은 더 이상 그렇게 할 수 없습니다. 실패합니다! ld는 다시 시도하고, 다시 실패하고, ld는 예상치 못한 일을 합니다.더 적은 메모리로 이동합니다.
이상하네요, 그럼 코드를 보는 게 좋을 것 같아요.드랫, 그건 명시적으로 하지 않습니다.mmap
오래된 평원의 내부에서 나온 것임에 틀림없습니다.malloc
이를 추적하려면 디버깅 기호를 사용하여 ld를 구축해야 합니다.불행하게도, 제가 bin-utils 2.21.1을 만들었을 때 문제가 사라졌습니다.아마도 새로운 버전의 빈 유틸리티에서 수정되었나요?
Debian/Sid/AMD64, gcc 4.6.2, binutils gold(Debian 2.22인치 GNU Binutils) 1.11).다음은 변경된 프로그램입니다(메모리 맵 표시).pmap
).
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define M 1000000
#define GIANT_SIZE (2000*M)
size_t g_arr[GIANT_SIZE];
int main( int argc, char **argv){
int i;
char cmd[80];
for(i = 0; i<10; i++){
printf("This should be zero: %d\n",g_arr[i*1000]);
}
sprintf (cmd, "pmap %d", (int)getpid());
system(cmd);
exit(0);
}
다음은 편집 내용입니다.
% time gcc -v -O big.c -o big
Using built-in specs.
COLLECT_GCC=/usr/bin/gcc-4.6.real
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.6.2-4' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++,go --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc --with-arch-32=i586 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.6.2 (Debian 4.6.2-4)
COLLECT_GCC_OPTIONS='-v' '-O' '-o' 'big' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/4.6/cc1 -quiet -v -imultilib . -imultiarch x86_64-linux-gnu big.c -quiet -dumpbase big.c -mtune=generic -march=x86-64 -auxbase big -O -version -o /tmp/ccWThBP5.s
GNU C (Debian 4.6.2-4) version 4.6.2 (x86_64-linux-gnu)
compiled by GNU C version 4.6.2, GMP version 5.0.2, MPFR version 3.1.0, MPC version 0.9
warning: MPFR header version 3.1.0 differs from library version 3.1.0-p3.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-linux-gnu/4.6/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/4.6/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
GNU C (Debian 4.6.2-4) version 4.6.2 (x86_64-linux-gnu)
compiled by GNU C version 4.6.2, GMP version 5.0.2, MPFR version 3.1.0, MPC version 0.9
warning: MPFR header version 3.1.0 differs from library version 3.1.0-p3.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 4b128876859f8f310615c7040fa3cb67
COLLECT_GCC_OPTIONS='-v' '-O' '-o' 'big' '-mtune=generic' '-march=x86-64'
as --64 -o /tmp/ccm7905b.o /tmp/ccWThBP5.s
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.6/:/usr/lib/gcc/x86_64-linux-gnu/4.6/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.6/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.6/:/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-O' '-o' 'big' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/4.6/collect2 --build-id --no-add-needed --eh-frame-hdr -m elf_x86_64 --hash-style=both -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o big /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.6/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../.. /tmp/ccm7905b.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.6/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crtn.o
gcc -v -O big.c -o big 0.07s user 0.01s system 90% cpu 0.089 total
그리고 그 실행:
% time ./big
This should be zero: 0
This should be zero: 0
This should be zero: 0
This should be zero: 0
This should be zero: 0
This should be zero: 0
This should be zero: 0
This should be zero: 0
This should be zero: 0
This should be zero: 0
8835: ./big
0000000000400000 4K r-x-- /home/basile/tmp/big
0000000000401000 4K rw--- /home/basile/tmp/big
0000000000402000 15625000K rw--- [ anon ]
00007f2d15a44000 1512K r-x-- /lib/x86_64-linux-gnu/libc-2.13.so
00007f2d15bbe000 2048K ----- /lib/x86_64-linux-gnu/libc-2.13.so
00007f2d15dbe000 16K r---- /lib/x86_64-linux-gnu/libc-2.13.so
00007f2d15dc2000 4K rw--- /lib/x86_64-linux-gnu/libc-2.13.so
00007f2d15dc3000 20K rw--- [ anon ]
00007f2d15dc8000 124K r-x-- /lib/x86_64-linux-gnu/ld-2.13.so
00007f2d15fb4000 12K rw--- [ anon ]
00007f2d15fe4000 12K rw--- [ anon ]
00007f2d15fe7000 4K r---- /lib/x86_64-linux-gnu/ld-2.13.so
00007f2d15fe8000 4K rw--- /lib/x86_64-linux-gnu/ld-2.13.so
00007f2d15fe9000 4K rw--- [ anon ]
00007ffff5b5b000 132K rw--- [ stack ]
00007ffff5bff000 4K r-x-- [ anon ]
ffffffffff600000 4K r-x-- [ anon ]
total 15628908K
./big 0.00s user 0.00s system 0% cpu 0.004 total
이러한 프로그램에는 최근 GCC(예: GCC 4.6)를 바이유틸스 골드 링커로 설치하는 것이 중요하다고 생각합니다.
저는 교환에 관련된 어떤 것도 듣지 못합니다.
OpenSusse 11.4 테스트(1주일 만에 12.1 테스트 실시)를 고문했습니다.
4GiBram + 2GiB 스왑을 사용하고 있으며 심각한 속도 저하를 감지하지 못했습니다. 시스템이 때때로 손상될 수 있지만 컴파일 시간은 짧았습니다.
가장 긴 시간은 헤비 스와핑 중에 6초였습니다.
[tester@ulises ~]$ free -m
total used free shared buffers cached
Mem: 3456 3426 30 0 4 249
-/+ buffers/cache: 3172 284
Swap: 2055 1382 672
[tester@ulises ~]$ time cc -Wall -O test2.c
test2.c: In function ‘main’:
test2.c:13:2: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘size_t’
real 0m6.501s
user 0m0.101s
sys 0m0.078s
[tester@ulises ~]$ free -m
total used free shared buffers cached
Mem: 3456 3389 67 0 5 289
-/+ buffers/cache: 3094 362
Swap: 2055 1455 599
[tester@ulises ~]$ free -m
total used free shared buffers cached
Mem: 3456 3373 82 0 4 264
-/+ buffers/cache: 3104 352
Swap: 2055 1442 612
[tester@ulises ~]$ time cc -Wall -O test2.c
test2.c: In function ‘main’:
test2.c:13:2: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘size_t’
real 0m1.122s
user 0m0.086s
sys 0m0.045s
[tester@ulises ~]$ time cc -Wall -O test2.c
test2.c: In function ‘main’:
test2.c:13:2: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘size_t’
real 0m0.095s
user 0m0.047s
sys 0m0.032s
[tester@ulises ~]$ free -m
total used free shared buffers cached
Mem: 3456 3376 79 0 4 252
-/+ buffers/cache: 3119 336
Swap: 2055 1436 618
[tester@ulises ~]$ time cc -Wall -O test2.c
test2.c: In function ‘main’:
test2.c:13:2: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘size_t’
real 0m0.641s
user 0m0.054s
sys 0m0.040s
실행하는 동안 Virtual Box VM, Eclipse, 대용량 pdf 파일, mifirefox만 800MiB 이상을 사용하여 로드 및 언로드했습니다.저는 한계를 넘지 않았습니다, 그렇지 않으면 많은 앱들이 OS에 의해 죽을 것입니다.파이어폭스를 죽이는 것을 선호합니다.:-)
저는 또한 극단적으로 정의했습니다.
#define M 1048576
#define GIANT_SIZE (20000*M)
그리고 나서도 아무것도 크게 변하지 않습니다.
[tester@ulises ~]$ time cc -Wall -O test2.c
test2.c:7:14: warning: integer overflow in expression
test2.c:7:8: error: size of array ‘g_arr’ is negative
test2.c:7:1: warning: variably modified ‘g_arr’ at file scope
test2.c: In function ‘main’:
test2.c:13:2: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘size_t’
real 0m0.661s
user 0m0.043s
sys 0m0.031s
Edit: 512MiB RAM 및 1.5Gb 스왑 기능이 있는 VM에서 Fedora16을 사용하여 다시 테스트했는데 어레이에 20000MB가 할당된 "최대 스트레스 버전"에 오류 메시지가 표시된 것을 제외하고는 유사했습니다.어레이 크기가 음수라는 오류가 발생했습니다.
[ricardo@localhost ~]$ time gcc -Wall test2.c
test2.c:7:14: warning: integer overflow in expression [-Woverflow]
test2.c:7:8: error: size of array ‘g_arr’ is negative
test2.c:7:1: warning: variably modified ‘g_arr’ at file scope [enabled by default]
test2.c: In function ‘main’:
test2.c:13:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘size_t’ [-Wformat]
real 0m1.053s
user 0m0.050s
sys 0m0.137s
open use 12.1 VM에서도 동일한 응답이 발생합니다.Fedora 16 설치는 매우 느리고 메모리가 부족합니다(설치하는 동안 800MiB와 OpenSuse 512MiB를 사용해야 했습니다). Fedora가 많은 스왑 공간을 사용하고 있었기 때문에 Fedora에서 스왑오프를 사용할 수 없었습니다.OpenSusse 12.1과 메모리 문제는 없었습니다. 둘 다 기본적으로 커널, gcc 등의 버전이 동일합니다.둘 다 KDE와 함께 데스크톱 환경으로 재고 설치를 사용합니다.
저는 당신에게 문제를 재현할 수 없었습니다, 아마도 gcc 관련 문제일 것입니다.4.5와 같은 이전 버전을 다운로드하여 어떻게 되는지 확인해 보십시오.
언급URL : https://stackoverflow.com/questions/8233363/linker-performance-related-to-swap-space
'programing' 카테고리의 다른 글
작업:app:upploadCrashlyticsMappingFileRelease 실패한 파일 컬렉션에 정확히 하나의 파일이 포함되어야 하지만 파일이 없습니다. (0) | 2023.06.06 |
---|---|
re.split("()+")로 문자열을 분할할 때 결과 목록에 공백이 하나 있습니다. 더 나은 방법이 있습니까? (0) | 2023.06.06 |
MariaDB - 다른 열 값에 따라 상수로 열 업데이트 (0) | 2023.06.06 |
vb.net 에서 에 대한 차단/종료 중첩 (0) | 2023.06.06 |
형식을 사용하여 문자열을 작성하는 방법 (0) | 2023.04.22 |